zoukankan      html  css  js  c++  java
  • 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('
    ');
    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
  • 相关阅读:
    从多渠道打包与友盟统计有这一篇就够了
    多渠道打包
    studio构建错误Element uses-permission#android.permission.ACCESS_NETWORK_STATE at AndroidManifest.xml:38:5-79 dupli
    ADB命令与monkey
    正则表达式和文本挖掘(Text Mining)
    一步一步教你使用Git
    Android常见开源解决方案
    Android Intent到底能做些什么
    支付宝集成
    Theano 学习三 conv2d
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8710710.html
Copyright © 2011-2022 走看看