【做题】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是相当灵活的,用于执行计算机程序能完成的 ...
随机推荐
- [6]Windows内核情景分析 --APC
APC:异步过程调用.这是一种常见的技术.前面进程启动的初始过程就是:主线程在内核构造好运行环境后,从KiThreadStartup开始运行,然后调用PspUserThreadStartup,在该线程 ...
- hdu2262 高斯消元
题目:有一个地图,一个人从某个点出发,问走到花园的期望步数为多少 设某点的期望步数为Ei. 那么目标的Ei=0. Ei=(Enext1+Enext2……Enextk)/k+1. 为什么是这个公式 因为 ...
- HttpServletRequestWrapper
1). why 需要改变从 Servlet 容器 (可能是任何的 Servlet 容器)中传入的 HttpServletRequest 对象的某个行为,该怎么办? 一. 继承 HttpServletR ...
- python安装cv2
pip install opencv-python
- There is no session with id XXX
系统采用 shiro + redis + spring来做的权限控制系统. 登录时报 there is no session with XXX 跟踪断点发现,系统查询session时,查不到red ...
- [转载]window.location.href的用法(动态输出跳转)
无论在静态页面还是动态输出页面中window.location.href都是不错的用了跳转的实现方案 javascript中的location.href有很多种用法,主要如下. self.loca ...
- nfs共享文件搭建
Linux NFS服务器的安装与配置详解 一.NFS服务简介 NFS是Network File System(网络文件系统).主要功能是通过网络让不同的服务器之间可以共享文件或者目录.NFS客户端 ...
- The Little Prince-12/08
The Little Prince-12/08 今天来点中文的经典语录+内心独白好不好呢? 狐狸说:“对我来说,你只是一个小男孩,就像其他成千上万个小男孩一样没有什么两样.我不需要你.你也不需要我.对 ...
- solr 使用指定数据源
1,将solr 解压,我们观察发现它其实即可以是web服务也可以做数据分析 数据库 2,我们在example目录下新建一个hai的文件夹,用于存放数据 参考solr 目录,将solr.xml 复制一份 ...
- NUL和NULL
此处讨论C语言中的NUL和NULL 1.NUL是ASCII字符集中'\0'字符的名字,它的字节模式为全0 2.NULL指一个其值为0的指针 3.它们都是整型值,其值也相同,所以可以互换使用 4.然而, ...