BZOJ 3924 ZJOI2015 幻想乡战略游戏 树链剖分

题目链接:https://www.luogu.org/problemnew/show/P3345(bzoj权限题)

 

题意概述:动态维护树的上所有点到这棵树的带权重心的距离和。N,Q<=100000.

 

分析:

  首先考虑一个性质,对于任意一个点i来说,如果存在一个儿子j使得sz[j]*2>tot,那么i一定不是树的重心,并且重心应该在j的子树中,否则重心就可以是i。(这里必须是事先积累的知识,证明简单,略)

  于是就可以考虑一个暴力辣!每次从根出发按照上面的条件进行查找,一旦发现一个点没有儿子满足上面的性质,那么这个点就应该是一个重心。

  但是这样一次次走很慢。注意到我们找的是深度最大的j满足sz[j]*2>tot(满足条件的j一定在一条链上面),这里有很多的做法,但是考虑到我们计算答案的时候可能用到树剖,所以我们选择在DFS序上面操作,维护区间的sz最大值,直接在线段树上来二分查找,一次查找当前重心的复杂度是O(logn)。

  关于答案的计算,我们发现对于点i为重心的时候,其答案分成两部分,一个是i的子树,一个是i的祖先。我们单独计算每个祖先不包含i的其余子树的贡献,全部加起来就是这次的答案。

  通过计算,一次的答案可以表示为:

    sum[1]+d[i]*(tot-sz[i])-sum{ f(j) | j为i到1路径上的节(包括i)) }

    f(i)=sz[i]*(d[i]-d[fa[i]])+(sz[fa[i]]-sz[i])*d[fa[i]]

    sum[i]表示i的子树中的点到i的带权距离和,sz[i]表示i的子树中所有点的权值和,d[i]表示i到1的路径长度,tot表示所有点的权值和。

  维护:树剖,维护所有的sz和f以及sz的最大值,重链顶端的点不要去维护,每一次跳到的时候单独计算其f(因为没有办法同时维护一个点所有的儿子的f)。每次修改一个点的权值之后,其到1路径上所有点的sz都会改变,我们发现这些点的f值会发生变化,同时在更新中我们到达的所有的点的重儿子的f也会发生变化,记得更新一下。

  时间复杂度O(N+Q*logN^2)

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<set>
  9 #include<map>
 10 #include<vector>
 11 #include<cctype>
 12 using namespace std;
 13 typedef long long LL;
 14 
 15 int N,Q;
 16 struct segment_tree{
 17     static const int maxn=100005;
 18     struct edge{ int to,next,w; }E[maxn<<1];
 19     int first[maxn],np,n,dist[maxn],_sz[maxn],fa[maxn],son[maxn],top[maxn];
 20     int dfs_clock,l[maxn],a[maxn],sz[maxn];
 21     int rt,np2,lc[maxn<<1],rc[maxn<<1],mx[maxn<<1],flag[maxn<<1],tot;
 22     LL g[maxn<<1],sum;
 23     segment_tree(){ sum=np=np2=rt=0; }
 24     void add_edge(int u,int v,int w){
 25         E[++np]=(edge){v,first[u],w};
 26         first[u]=np;
 27     }
 28     void DFS1(int i,int f,int l){
 29         fa[i]=f,dist[i]=l;
 30         _sz[i]=1,sz[i]=0;
 31         for(int p=first[i];p;p=E[p].next){
 32             int j=E[p].to;
 33             if(j==f) continue;
 34             DFS1(j,i,l+E[p].w);
 35             _sz[i]+=_sz[j];
 36             if(_sz[j]>_sz[son[i]]) son[i]=j;
 37         }
 38     }
 39     void DFS2(int i,int f,int tp){
 40         top[i]=tp,l[i]=++dfs_clock;
 41         a[dfs_clock]=i;
 42         if(son[i]) DFS2(son[i],i,tp);
 43         for(int p=first[i];p;p=E[p].next){
 44             int j=E[p].to;
 45             if(j==f||j==son[i]) continue;
 46             DFS2(j,i,j);
 47         }
 48     }
 49     void pushup(int now){
 50         mx[now]=max(mx[lc[now]],mx[rc[now]]);
 51         g[now]=g[lc[now]]+g[rc[now]];
 52     }
 53     void pushdown(int now,int L,int R){
 54         if(!flag[now]) return;
 55         int m=L+R>>1;
 56         if(top[a[L]]==a[L]) g[lc[now]]+=1ll*flag[now]*(dist[a[m]]-dist[a[L]]);
 57         else g[lc[now]]+=1ll*flag[now]*(dist[a[m]]-dist[fa[a[L]]]);
 58         if(top[a[m+1]]==a[m+1]) g[rc[now]]+=1ll*flag[now]*(dist[a[R]]-dist[a[m+1]]);
 59         else g[rc[now]]+=1ll*flag[now]*(dist[a[R]]-dist[a[m]]);
 60         mx[lc[now]]+=flag[now],mx[rc[now]]+=flag[now];
 61         flag[lc[now]]+=flag[now],flag[rc[now]]+=flag[now];
 62         flag[now]=0;
 63     }
 64     void build(int &now,int L,int R){
 65         now=++np2,lc[now]=rc[now]=0;
 66         g[now]=mx[now]=flag[now]=0;
 67         if(L==R) return;
 68         int m=L+R>>1;
 69         build(lc[now],L,m); build(rc[now],m+1,R);
 70     }
 71     int query_p(int now,int L,int R){
 72         if(L==R) return a[L];
 73         pushdown(now,L,R);
 74         int m=L+R>>1;
 75         if(mx[rc[now]]*2>tot) return query_p(rc[now],m+1,R);
 76         return query_p(lc[now],L,m);
 77     }
 78     void query(int now,int L,int R,int pos){
 79         if(L==R){
 80             sz[a[L]]+=flag[now],flag[now]=0;
 81             return;
 82         }
 83         pushdown(now,L,R);
 84         int m=L+R>>1;
 85         if(pos<=m) query(lc[now],L,m,pos);
 86         else query(rc[now],m+1,R,pos);
 87     }
 88     LL query_g(int now,int L,int R,int A,int B){
 89         if(A<=L&&R<=B) return g[now];
 90         pushdown(now,L,R);
 91         int m=L+R>>1;
 92         if(B<=m) return query_g(lc[now],L,m,A,B);
 93         if(A>m) return query_g(rc[now],m+1,R,A,B);
 94         return query_g(lc[now],L,m,A,B)+query_g(rc[now],m+1,R,A,B);
 95     }
 96     void update1(int now,int L,int R,int A,int B,int delt){
 97         if(A<=L&&R<=B){
 98             mx[now]+=delt,flag[now]+=delt;
 99             if(top[a[L]]==a[L]) g[now]+=1ll*delt*(dist[a[R]]-dist[a[L]]);
100             else g[now]+=1ll*delt*(dist[a[R]]-dist[fa[a[L]]]);
101             return;
102         }
103         pushdown(now,L,R);
104         int m=L+R>>1;
105         if(B<=m) update1(lc[now],L,m,A,B,delt);
106         else if(A>m) update1(rc[now],m+1,R,A,B,delt);
107         else update1(lc[now],L,m,A,B,delt),update1(rc[now],m+1,R,A,B,delt);
108         pushup(now);
109     }
110     void update2(int now,int L,int R,int pos,int delt){
111         if(L==R){
112             sz[a[L]]+=flag[now],flag[now]=0;
113             if(top[a[L]]!=a[L]) g[now]+=1ll*delt*dist[fa[a[L]]];
114             return;
115         }
116         pushdown(now,L,R);
117         int m=L+R>>1;
118         if(pos<=m) update2(lc[now],L,m,pos,delt);
119         else update2(rc[now],m+1,R,pos,delt);
120         pushup(now);
121     }
122     void update(int p,int delt){
123         tot+=delt,sum+=1ll*delt*dist[p];
124         while(p){
125             update1(rt,1,n,l[top[p]],l[p],delt);
126             if(son[p]) update2(rt,1,n,l[son[p]],delt);
127             p=fa[top[p]];
128         }
129     }
130     LL ans(){
131         int p=query_p(rt,1,n);
132         query(rt,1,n,l[p]);
133         LL re=sum+1ll*dist[p]*(tot-sz[p]);
134         while(p){
135             re-=query_g(rt,1,n,l[top[p]],l[p]);
136             p=top[p];
137             query(rt,1,n,l[p]); query(rt,1,n,l[fa[p]]);
138             re-=1ll*sz[p]*(dist[p]-dist[fa[p]])+1ll*(sz[fa[p]]-sz[p])*dist[fa[p]];
139             p=fa[p];
140         }
141         return re;
142     }
143 }st;
144 
145 bool nega;
146 void _scanf(int &x)
147 {
148     x=0,nega=0;
149     char ch=getchar();
150     while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
151     if(ch=='-') nega=1,ch=getchar();
152     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
153     if(nega) x=-x;
154 }
155 int out_cnt,out[20];
156 void _printf(LL x)
157 {
158     out[++out_cnt]=x%10,x/=10;
159     while(x) out[++out_cnt]=x%10,x/=10;
160     while(out_cnt) putchar('0'+out[out_cnt--]);
161     putchar('\n');
162 }
163 void data_in()
164 {
165     _scanf(N);_scanf(Q); st.n=N;
166     int x,y,z;
167     for(int i=1;i<N;i++){
168         _scanf(x);_scanf(y);_scanf(z);
169         st.add_edge(x,y,z); st.add_edge(y,x,z);
170     }
171 }
172 void work()
173 {
174     int u,e;
175     st.DFS1(1,0,0);
176     st.DFS2(1,0,1);
177     st.build(st.rt,1,st.n);
178     for(int i=1;i<=Q;i++){
179         _scanf(u);_scanf(e);
180         st.update(u,e);
181         _printf(st.ans());
182     }
183 }
184 int main()
185 {
186     data_in();
187     work();
188     return 0;
189 }
View Code

 

posted @ 2018-04-03 19:41  KKKorange  阅读(322)  评论(2编辑  收藏  举报