bzoj3924 幻想乡战略游戏 树链剖分&分治树
2016-03-13 17:19
204 查看
(对于和我一样没有权限的穷孩子,可以点这里提交)
一句话题意:维护带修改的带权重心到其余点的带权距离和。
首先看怎么求出带权重心。假设现在考虑一个点x,我们维护一个值f[x]表示x所在子树所有节点的权值和。那么如果存在一个点y,y是x的一个子节点,使得f[y]*2>树种所有点的权值和(显然反证易得这样的y只有一个),那么y一定比x更优;反之x比y更优。
那么就从根节点出发不断找y,然后向下走即可。但是这样可能会走很多步。因此首先得到树链剖分后的dfs序,然后用线段树维护某一个区间f[]的最大值。由于显然向下走时dfs序是不断增大的,这样可以在线段树中二分的到最终的重心的dfs序。
那么现在要求出中心到其余点的带权距离和。可以用树链剖分维护,或者用对树进行点分治之后得到的那棵树来维护。首先考虑一下朴素的做法。
枚举重心到根节点路径上的某一个点t,显然t的子树中除了x那一部分中的点与x的lca都是t(有点拗口)。那么就可以对一个点维护子树中每个点的权值*到这个点的距离的和,再维护一个权值和,然后这一部分的答案就是权值和*d(t,x)+权值*距离的和。这样就和树的层数有关了,发现这个可以用分治树来降低层数,于是就做好了。
时间复杂度O(Mlog^N),这个太难讲了不懂看代码把。。。
AC代码如下:
by lych
2016.3.13
一句话题意:维护带修改的带权重心到其余点的带权距离和。
首先看怎么求出带权重心。假设现在考虑一个点x,我们维护一个值f[x]表示x所在子树所有节点的权值和。那么如果存在一个点y,y是x的一个子节点,使得f[y]*2>树种所有点的权值和(显然反证易得这样的y只有一个),那么y一定比x更优;反之x比y更优。
那么就从根节点出发不断找y,然后向下走即可。但是这样可能会走很多步。因此首先得到树链剖分后的dfs序,然后用线段树维护某一个区间f[]的最大值。由于显然向下走时dfs序是不断增大的,这样可以在线段树中二分的到最终的重心的dfs序。
那么现在要求出中心到其余点的带权距离和。可以用树链剖分维护,或者用对树进行点分治之后得到的那棵树来维护。首先考虑一下朴素的做法。
枚举重心到根节点路径上的某一个点t,显然t的子树中除了x那一部分中的点与x的lca都是t(有点拗口)。那么就可以对一个点维护子树中每个点的权值*到这个点的距离的和,再维护一个权值和,然后这一部分的答案就是权值和*d(t,x)+权值*距离的和。这样就和树的层数有关了,发现这个可以用分治树来降低层数,于是就做好了。
时间复杂度O(Mlog^N),这个太难讲了不懂看代码把。。。
AC代码如下:
#include<iostream> #include<cstdio> #define N 100005 #define M 2000005 #define ll long long using namespace std; int n,m,tot=1,cnt,dfsclk,rt,all,pnt[M],nxt[M],len[M],edg[M]; int fa ,sz ,son ,pos ,anc ,icr[N<<2],id ,a ,f ; ll val[N<<2],sum[4][M]; struct graph{ int fst ; void add(int x,int y,int z,int w){ pnt[++tot]=y; len[tot]=z; edg[tot]=w; nxt[tot]=fst[x]; fst[x]=tot; } }g1,g2; int read(){ int x=0,fu=1; char ch=getchar(); while (ch<'0' || ch>'9'){ if (ch=='-') fu=-1; ch=getchar(); } while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*fu; } void pushdown(int k){ if (icr[k]){ icr[k<<1]+=icr[k]; val[k<<1]+=icr[k]; icr[k<<1|1]+=icr[k]; val[k<<1|1]+=icr[k]; icr[k]=0; } } void ins(int k,int l,int r,int x,int y,int t){ if (l==x && r==y){ icr[k]+=t; val[k]+=t; return; } int mid=(l+r)>>1; pushdown(k); if (y<=mid) ins(k<<1,l,mid,x,y,t); else if (x>mid) ins(k<<1|1,mid+1,r,x,y,t); else{ ins(k<<1,l,mid,x,mid,t); ins(k<<1|1,mid+1,r,mid+1,y,t); } val[k]=max(val[k<<1],val[k<<1|1]); } void dfs(int x){ sz[x]=1; int p; for (p=g1.fst[x]; p; p=nxt[p]){ int y=pnt[p]; if (y!=fa[x]){ fa[y]=x; dfs(y); sz[x]+=sz[y]; if (sz[y]>sz[son[x]]) son[x]=y; } } } void divide(int x,int tp){ anc[x]=tp; pos[x]=++dfsclk; id[dfsclk]=x; if (son[x]) divide(son[x],tp); int p; for (p=g1.fst[x]; p; p=nxt[p]){ int y=pnt[p]; if (y!=fa[x] && y!=son[x]) divide(y,y); } } void getrt(int x,int last){ sz[x]=1; f[x]=0; int p; for (p=g1.fst[x]; p; p=nxt[p]) if (edg[p]){ int y=pnt[p]; if (y!=last){ getrt(y,x); sz[x]+=sz[y]; f[x]=max(f[x],sz[y]); } } f[x]=max(f[x],all-sz[x]); if (f[x]<f[rt]) rt=x; } void getedg(int x,int last,int t){ g2.add(x,rt,t,cnt); int p; for (p=g1.fst[x]; p; p=nxt[p]) if (edg[p] && pnt[p]!=last) getedg(pnt[p],x,t+len[p]); } void solve(int x){ int p; for (p=g1.fst[x]; p; p=nxt[p]) if (edg[p]){ cnt++; getedg(pnt[p],x,len[p]); } for (p=g1.fst[x]; p; p=nxt[p]) if (edg[p]){ int y=pnt[p]; edg[p^1]=0; f[0]=all=sz[y]; rt=0; getrt(y,rt); solve(rt); } } int main(){ //freopen("zjoi15_tree.in","r",stdin); freopen("zjoi15_tree.out","w",stdout); n=read(); m=read(); int i; for (i=1; i<n; i++){ int x=read(),y=read(),z=read(); g1.add(x,y,z,1); g1.add(y,x,z,1); } f[0]=all=n; getrt(1,0); solve(rt); dfs(1); divide(1,1); while (m--){ int x=read(),y=read(); for (i=x; i; i=fa[anc[i]]) ins(1,1,n,pos[anc[i]],pos[i],y); a[x]+=y; for (i=g2.fst[x]; i; i=nxt[i]){ sum[0][pnt[i]]+=y; sum[1][pnt[i]]+=(ll)len[i]*y; sum[2][edg[i]]+=y; sum[3][edg[i]]+=(ll)len[i]*y; } int l=1,r=n,i=1,mid; while (l<r){ pushdown(i); mid=(l+r)>>1; if ((val[i<<1|1]<<1)>=val[1]){ l=mid+1; i=i<<1|1; } else{ r=mid; i<<=1; } } ll ans=sum[1][id[l]]; for (i=g2.fst[id[l]]; i; i=nxt[i]){ x=pnt[i]; y=edg[i]; ans+=(sum[0][x]-sum[2][y]+a[x])*len[i]+sum[1][x]-sum[3][y]; } printf("%lld\n",ans); } return 0; }
by lych
2016.3.13
相关文章推荐
- 第三周:构造一个简单的LINUX系统MENUOS
- java Script入门
- String,StringBuffer与StringBuilder的区别及应用场景
- 转载 加 原创 session 和 cookie 内在联系
- [Mac OS X Cocoa编程]如何获取其他应用程序的窗体标题以及相关信息?
- Linux内核启动分析
- js 正在表达式 总结
- IOS开发 统计XCODE 代码行数
- Right-BICEP测试四则运算2
- 两种数据访问方式:从ADO 到ADO.NET
- c# 多线程中lock用法经典实例及lock("xxx"),lock(typeof(Class)),Lock(this)的区别
- 七、Nginx学习笔记七Nginx的Web缓存服务
- 第二周学习进度表
- Flex-box-03 伸缩项目属性
- asp.net 服务端控件的使用
- Hibernate Modules/Artifacts(Hibernate模块/工件)
- this computer does not support Intel Virtualization Technology (VT-x) .Haxm can'not be installed
- Android程序开发记录:发布APK,权限等
- 一个ajax实例
- 又一个ajax实例,结合jQuery