【做题】zoj3649 Social Net——倍增
这题是吴老师推荐的,于是我就去做了。
根据题意,在完成最大生成树后,对于树上从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——倍增的更多相关文章
- CodeM美团点评编程大赛复赛 做题感悟&题解
[T1] [简要题意] 长度为N的括号序列,随机确定括号的方向:对于一个已确定的序列,每次消除相邻的左右括号(右左不行),消除后可以进一步合并和消除直到不能消为止.求剩下的括号的期望.\(N \l ...
- noip做题记录+挑战一句话题解?
因为灵巧实在太弱辽不得不做点noip续下命QQAQQQ 2018 积木大赛/铺设道路 傻逼原题? 然后傻逼的我居然检查了半天是不是有陷阱最后花了差不多一个小时才做掉我做过的原题...真的傻逼了我:( ...
- Sam做题记录
Sam做题记录 Hihocoder 后缀自动机二·重复旋律5 求一个串中本质不同的子串数 显然,答案是 \(\sum len[i]-len[fa[i]]\) Hihocoder 后缀自动机三·重复旋律 ...
- PKUWC/SC 做题笔记
去年不知道干了些啥,什么省选/营题都没做. 现在赶应该还来得及(?) 「PKUWC2018」Minimax Done 2019.12.04 9:38:55 线段树合并船新玩法??? \(O(n^2)\ ...
- POI做题笔记
POI2011 Conspiracy (2-SAT) Description \(n\leq 5000\) Solution 发现可拆点然后使用2-SAT做,由于特殊的关系,可以证明每次只能交换两个集 ...
- NOIP2016考前做题(口胡)记录
NOIP以前可能会持续更新 写在前面 NOIP好像马上就要到了,感觉在校内训练里面经常被虐有一种要滚粗的感觉(雾.不管是普及组还是提高组,我都参加了好几年了,结果一个省一都没有,今年如果还没有的话感觉 ...
- SAM 做题笔记(各种技巧,持续更新,SA)
SAM 感性瞎扯. 这里是 SAM 做题笔记. 本来是在一篇随笔里面,然后 Latex 太多加载不过来就分成了两篇. 标 * 的是推荐一做的题目. trick 是我总结的技巧. I. P3804 [模 ...
- UOJ 做题记录
UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...
- C语言程序设计做题笔记之C语言基础知识(下)
C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...
随机推荐
- workerman程序调试
现象1 启动后报错类似如下: php start.php start PHP Warning: stream_socket_server(): unable to connect to tcp://x ...
- 20155228 2017-5-31 课堂测试:编写MyOD.java
20155228 2017-5-31 课堂测试:编写MyOD.java 题目和要求 编写MyOD.java:用java MyOD XXX实现Linux下od -tx -tc XXX的功能 提交测试代码 ...
- Linux中常用的50个命令
1. [命令]:cat [功能说明]: concatenate files and print on the standard output #连接文件并打印到标准输出,有标准输出的都可以用重定向定向 ...
- Spring NoSuchBeanDefinitionException
转http://www.baeldung.com/spring-nosuchbeandefinitionexception 1. Overview In this article, we are di ...
- XmlDocument操作
一.基本操作:XmlDocument 写 class Program { static void Main(string[] args) { // 使用DOM操作,常用的类:XmlDocument.X ...
- MaxiSYS Elite
The Maxisys Elite is Autel UK’s top of the range diagnostic and analysis scanner with advanced J2534 ...
- php学习路线(转)
作者:Summer链接:https://www.zhihu.com/question/20034403/answer/135433912来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...
- Maven配置阿里云镜像仓库
配置文件:D:\MyDev\Maven\apache-maven-3.0.5\conf\settings.xml <mirrors> <mirror> <id>al ...
- sqlite3增删改查简单封装
import sqlite3 class DBTool(object): def __init__(self): """ 初始化函数,创建数据库连接 "&quo ...
- 您的windows许可证即将过期 win10的解决办法
出现这个错误是因为安装的版本不是正版系统,每隔一段时间需要激活 这次激活也费了一些时间,记录如下希望能对大家有所帮助 (1)首先可以查看自己的许可什么什么时候会过期 windows+R调出命令运行窗口 ...