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

根据题意,在完成最大生成树后,对于树上从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. php aes128加密

    //[加密数据]AES 128 ECB模式 public function aesEncrypt($str){ $screct_key = Yii::$app->params['encryptK ...

  2. 多线程:Operation(一)

    1. 进程和线程 1.1 进程 进程:正在运行的应用程序叫进程 进程之间都是独立的,运行在专用且受保护的内存空间中 两个进程之间无法通讯 通俗的理解,手机上同时开启了两个App.这两个App肯定是在不 ...

  3. Java WEB 笔记

    1. 部署并启动 tomcat 服务器 1). 解压 apache-tomcat-version 到一个非中文目录下 2). 配置一个环境变量,JAVA_HOME(指向 JDK 安装目录)或 JRE_ ...

  4. Presto 学习

    Presto 基础知识与概念学习可以参考这些博客: presto 0.166概述 https://www.cnblogs.com/sorco/p/7060166.html Presto学习-prest ...

  5. Axure RP Extension for Chrome修复

    Axure RP Extension for Chrome安装之前一直用 Firefox 浏览器浏览原型文件,一直用不惯,而且用 Firefox 的唯一目的就是看原型.其他都是用 Chrome 浏览器 ...

  6. 转:【专题二】HTTP协议详解

    我们在用Asp.net技术开发Web应用程序后,当用户在浏览器输入一个网址时就是再向服务器发送一个HTTP请求,此时就使用了应用层的HTTP协议,在上一个专题我们简单介绍了网络协议的知识,主要是为了后 ...

  7. android排除报很多错方法 Execution failed for task ':app:compileDebugJavaWithJavac' in Android Studio

    android排除报很多错方法1.回撤对应layout的xml改动2.回撤对应java的改动3.重命名文件后导致的资源不对应 Execution failed for task ':app:compi ...

  8. php 获取ip地址的5种方法,插入用户登录日志实例

    php 获取ip地址的5种方法,插入用户登录日志实例,推荐使用第二种方法 <?php //方法1: $ip = $_SERVER["REMOTE_ADDR"]; echo $ ...

  9. navicat 连接postgresql报错pg_hba.conf

    PostgreSQ数据库为了安全,它不会监听除本地以外的所有连接请求,当用户通过JDBC访问是,会报一些如下的异常: org.postgresql.util.PSQLException: FATAL: ...

  10. 前端框架VUE----vue的使用

    一.安装 对于新手来说,强烈建议大家使用<script>引入 二. 引入vue.js文件 我们能发现,引入vue.js文件之后,Vue被注册为一个全局的变量,它是一个构造函数. 三.使用V ...