这题是吴老师推荐的,于是我就去做了。

根据题意,在完成最大生成树后,对于树上从x到y的一条路径,求出最大的ck-cj(j<=k,ci为路径上第i个点的权值)。

我一开始的想法是二分,记路径xy的中点是mid,路径ab的答案记为ans(a,b),最大值为mx(a,b),最小值为mn(a,b),那么,ans(x,y)=max{ans(x,mid),ans(y,mid),mx(mid,y)-mn(x,mid)}。

但我忘记了一个问题,对于时间复杂度T(n)=2T(n/2)+logn,由主定理可知,解为T(n)=O(n)。换言之这并没有比暴力优越。

然而,正如同求路径上的最大最小值一样,我们可以通过倍增的方法把ans预处理出来,然后在O(logn)的时间内得到解。

具体说就是把一个点向上2^i的答案和一个点第2^i-1个祖先到i的答案都预处理出来。而预处理和最终计算答案的方法和上述的二分是完全一致的。

所以,我们可以通过O(n*logn)的时间完成预处理,再对与每个询问O(logn)地得到解。

时间复杂度O(n*logn+q*logn)。

 #include <bits/stdc++.h>
using namespace std;
template <typename tp> inline void read(tp& x)
{
x=;
char tmp=getchar();bool key=;
for(;!((tmp>=''&&tmp<='')||tmp=='-');) tmp=getchar();
if(tmp=='-') key=,tmp=getchar();
for(;tmp>=''&&tmp<='';) x=(x<<)+(x<<)+tmp-'',tmp=getchar();
if(key) x=-x;
}
const int N=,M=,MAXPOS=;
struct edge_for_buildtree{
int a,b,v;
bool operator < (const edge_for_buildtree& x)const
{
return v>x.v;
}
}ed[M];
struct edge_for_lca{
int la,b;
}con[N<<];
int tot,fir[N];
inline void add(int from,int to)
{
con[++tot].la=fir[from];
con[tot].b=to;
fir[from]=tot;
}
int n,m,q,val[N],flag[N],anc[N][MAXPOS+],mn[N][MAXPOS+],mx[N][MAXPOS+],deep[N];
int recu[N][MAXPOS+],recd[N][MAXPOS+];
inline void init()
{
memset(anc,,sizeof anc);
memset(mn,0x3f,sizeof mn);
memset(mx,,sizeof mx);
memset(fir,,sizeof fir);
memset(recu,,sizeof recu);
memset(recd,,sizeof recd);
tot=;
}
int get_flag(int pos)
{
return flag[pos]==pos? pos : flag[pos]=get_flag(flag[pos]);
}
inline void kruskal()
{
int x,y,ans=,cnt=;
sort(ed+,ed+m+);
for(register int i=;i<=n;++i) flag[i]=i;
for(register int i=;i<=m;++i)
{
x=ed[i].a;y=ed[i].b;
x=get_flag(x);y=get_flag(y);
if(x==y) continue;
add(ed[i].a,ed[i].b);
add(ed[i].b,ed[i].a);
ans+=ed[i].v;
flag[x]=y;
if(++cnt==n-) break;
}
printf("%d\n",ans);
}
void dfs_init(int pos)
{
deep[pos]=deep[anc[pos][]]+;
mn[pos][]=mx[pos][]=val[pos];
recu[pos][]=recd[pos][]=;
for(int i=;i<=MAXPOS;++i)
{
anc[pos][i]=anc[anc[pos][i-]][i-];
mn[pos][i]=min(mn[pos][i-],mn[anc[pos][i-]][i-]);
mx[pos][i]=max(mx[pos][i-],mx[anc[pos][i-]][i-]);
recu[pos][i]=max(max(recu[pos][i-],recu[anc[pos][i-]][i-]),mx[anc[pos][i-]][i-]-mn[pos][i-]);
recd[pos][i]=max(max(recd[pos][i-],recd[anc[pos][i-]][i-]),mx[pos][i-]-mn[anc[pos][i-]][i-]);
if(anc[pos][i]==) break;
}
for(int i=fir[pos];i;i=con[i].la)
{
if(con[i].b==anc[pos][]) continue;
anc[con[i].b][]=pos;
dfs_init(con[i].b);
}
}
inline int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
for(int i=MAXPOS;i>=;--i)
{
if(deep[anc[x][i]]>=deep[y]) x=anc[x][i];
}
if(x==y) return x;
for(int i=MAXPOS;i>=;--i)
{
if(anc[x][i]!=anc[y][i])
x=anc[x][i],y=anc[y][i];
}
return anc[x][];
}
inline int get_mn(int x,int y)//y is the ancestor of x
{
if(x==y) return val[x];
int res=val[x],len=deep[x]-deep[y]+;
for(int i=MAXPOS;i>=;--i)
{
if(len>=(<<i))
res=min(res,mn[x][i]),x=anc[x][i],len-=(<<i);
}
return res;
}
inline int get_mx(int x,int y)//y is the ancestor of x
{
if(x==y) return val[x];
int res=val[x],len=deep[x]-deep[y]+;
for(int i=MAXPOS;i>=;--i)
{
if(len>=(<<i))
res=max(res,mx[x][i]),x=anc[x][i],len-=(<<i);
}
return res;
}
inline int ask_mn(int x,int y,int lc)
{
return min(get_mn(x,lc),get_mn(y,lc));
}
inline int ask_mx(int x,int y,int lc)
{
return max(get_mx(x,lc),get_mx(y,lc));
}
inline int get_recu(int x,int y)//y is the ancestor of x
{
if(x==y) return ;
int mnpre=,res=;
for(int i=MAXPOS;i>=;i--)
{
if(deep[anc[x][i]]>=deep[y])
{
res=max(res,recu[x][i]);
res=max(res,mx[x][i]-mnpre);
mnpre=min(mnpre,mn[x][i]);
x=anc[x][i];
}
}
return res;
}
inline int get_recd(int x,int y)
{
if(x==y) return ;
int mxpre=,res=;
for(int i=MAXPOS;i>=;i--)
{
if(deep[anc[x][i]]>=deep[y])
{
res=max(res,recd[x][i]);
res=max(res,mxpre-mn[x][i]);
mxpre=max(mxpre,mx[x][i]);
x=anc[x][i];
}
}
return res;
}
inline int solve(int x,int y)
{
if(x==y) return ;
if(anc[x][]==y||anc[y][]==x) return max(,val[y]-val[x]);
int z=lca(x,y);
int res=max(get_recu(x,z),get_recd(y,z));
res=max(res,ask_mx(y,z,z)-ask_mn(x,z,z));
return res;
}
int main()
{
int x,y,v;
while(scanf("%d",&n)!=EOF)
{
init();
for(register int i=;i<=n;++i) read(val[i]);
read(m);
for(register int i=;i<=m;++i)
{
read(x);read(y);read(v);
ed[i]=(edge_for_buildtree){x,y,v};
}
kruskal();
dfs_init();
read(q);
for(;q--;)
{
read(x);read(y);
printf("%d\n",solve(x,y));
}
}
return ;
}

小结:通常对于无修改的题目,这种看似无用的二分往往可以通过倍增来优化。

【做题】zoj3649 Social Net——倍增的更多相关文章

  1. CodeM美团点评编程大赛复赛 做题感悟&题解

    [T1] [简要题意]   长度为N的括号序列,随机确定括号的方向:对于一个已确定的序列,每次消除相邻的左右括号(右左不行),消除后可以进一步合并和消除直到不能消为止.求剩下的括号的期望.\(N \l ...

  2. noip做题记录+挑战一句话题解?

    因为灵巧实在太弱辽不得不做点noip续下命QQAQQQ 2018 积木大赛/铺设道路 傻逼原题? 然后傻逼的我居然检查了半天是不是有陷阱最后花了差不多一个小时才做掉我做过的原题...真的傻逼了我:( ...

  3. Sam做题记录

    Sam做题记录 Hihocoder 后缀自动机二·重复旋律5 求一个串中本质不同的子串数 显然,答案是 \(\sum len[i]-len[fa[i]]\) Hihocoder 后缀自动机三·重复旋律 ...

  4. PKUWC/SC 做题笔记

    去年不知道干了些啥,什么省选/营题都没做. 现在赶应该还来得及(?) 「PKUWC2018」Minimax Done 2019.12.04 9:38:55 线段树合并船新玩法??? \(O(n^2)\ ...

  5. POI做题笔记

    POI2011 Conspiracy (2-SAT) Description \(n\leq 5000\) Solution 发现可拆点然后使用2-SAT做,由于特殊的关系,可以证明每次只能交换两个集 ...

  6. NOIP2016考前做题(口胡)记录

    NOIP以前可能会持续更新 写在前面 NOIP好像马上就要到了,感觉在校内训练里面经常被虐有一种要滚粗的感觉(雾.不管是普及组还是提高组,我都参加了好几年了,结果一个省一都没有,今年如果还没有的话感觉 ...

  7. SAM 做题笔记(各种技巧,持续更新,SA)

    SAM 感性瞎扯. 这里是 SAM 做题笔记. 本来是在一篇随笔里面,然后 Latex 太多加载不过来就分成了两篇. 标 * 的是推荐一做的题目. trick 是我总结的技巧. I. P3804 [模 ...

  8. UOJ 做题记录

    UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...

  9. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

随机推荐

  1. leetCode-linkedListCycle判断链表是否有环

    题目 Given a linked list, determine if it has a cycle in it. Follow up: Can you solve it without using ...

  2. nw.js package一般设置

    { "name": "app name", "main": "mainpage",                    ...

  3. How to compute f1 score for each epoch in Keras

    https://medium.com/@thongonary/how-to-compute-f1-score-for-each-epoch-in-keras-a1acd17715a2 https:// ...

  4. 深度解读 AlphaGo 算法原理

    http://blog.csdn.net/songrotek/article/details/51065143 http://blog.csdn.net/dinosoft/article/detail ...

  5. centos中yum命令删除还原的补救方法介绍

    前言 yum,是Yellow dog Updater Modified的简称,起初是由yellow dog这一发行版的开发者Terra Soft研发,用python写成,那时还叫做yup(yellow ...

  6. timestamp与timedelta,管理信息系统概念与基础

    1.将字符串‘2017年10月9日星期一9时10分0秒 UTC+8:00’转换为timestamp. 2.100天前是几号?   今年还有多少天? #timestamp与timedelta from ...

  7. Eclipse中tomcat更改部署路径 deply path

    默认是部署在项目元数据文件夹.metadata文件夹下,需要更改到tomcat/webapps目录下 Eclipse中tomcat service设置 选择window ----show view-- ...

  8. linux 文件压缩与解压缩

  9. [转载]WebService服务的三种途径Endpoint Disco WSDL 有什么不同

    Endpoint: http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx   web服务的URI地址,你访问之后,就会出现web服务的相 ...

  10. [转载]Oracle数据库基础--SQL查询经典例题

    Oracle基础练习题,采用Oracle数据库自带的表,适合初学者,其中包括了一些简单的查询,已经具有Oracle自身特点的单行函数的应用 本文使用的实例表结构与表的数据如下: emp员工表结构如下: ...