【Bzoj 3924】[ZJOI2015]幻想乡战略游戏

[ZJOI2015]幻想乡战略游戏

动态点分治

  题目链接:https://www.luogu.org/problemnew/show/P3345

  参考:https://www.luogu.org/blog/zcysky/solution-p3345

  首先对于点分治下去的重心,我们连边后可以得到一个新的树(点分树),树上的每个点可以维护的是这课子树的信息

  点分树的深度不会超过log n

  对于修改,我们可以从这课新树对应的节点往上更新内容

 

  这题有一个贪心的方法,朝着最优点走会越走越优,反之越差

  点分树的节点维护

    这颗子树的军队总数              sum

    这颗子树的军队到这个点的代价和        dis1

    这颗子树的军队到这个点的点分树的父节点的代价和   dis2

    

  对于修改,我们从这个原树节点 对应的 点分树节点 往上更新即可(n log n)

  对于查询,我们会发现如果最优点在2个重心之间(其中一个重心是另外一个重心的点分树的儿子)那么儿子重心可能会比父重心差,就不会往儿子重心走了

  于是点分树建边时,可以维护一个信息:父重心的原树儿子w(在2个重心之间)

 

  于是查询我们可以判断,如果点分树上,这个点连向儿子的边的w比这个点优,就往这个点的儿子重心走。时间logn

  怎么求出一个点的代价和呢?

    找到这个点对应点分树上的点u

    对于这颗子树的代价,直接+dis1u即可

    对于子树外的代价,我们从u往上走

    每次走到一个点v,fa为v 的父亲 +(dis_fa-dis2_v)+(sum_fa-sum_v)*dist  (dist为fa到u的距离)

  时间logn

  于是查询总时间为 n log n log n

  于是这题就做完了

  求两点距离时,可以用到st表找lca,查询为O1

  总时间n log^2 n

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #define ll long long
  4 using namespace std;
  5 const ll M=2e5;
  6 ll n,m;
  7 ll read(){
  8     ll rex=0,f=1;char ch=getchar();
  9     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 10     while(ch>='0'&&ch<='9'){rex=rex*10+ch-'0';ch=getchar();}
 11     return rex*f;
 12 }
 13 struct P{ll to,ne,w;};
 14 struct Lca{
 15     ll num,tot,pw[23],L[M],head[M],dep[M],fir[M],f[M<<1][23];
 16     P e[M<<1];
 17     void dfs(ll u,ll fa,ll w){
 18         f[fir[u]=++tot][0]=u;dep[u]=dep[fa]+w;
 19         for(ll i=head[u];i;i=e[i].ne){
 20             ll v=e[i].to;
 21             if(v!=fa){dfs(v,u,e[i].w);f[++tot][0]=u;}
 22         }
 23     }
 24     void RMQ(){
 25         pw[0]=1;L[1]=0;
 26         for(ll i=1;i<=20;++i)pw[i]=pw[i-1]<<1;
 27         for(ll i=2;i<=tot;++i)L[i]=L[i>>1]+1;
 28         for(ll j=1;j<=20;++j){
 29             for(ll i=1;i+pw[j]-1<=tot;++i){
 30                 f[i][j]=dep[f[i][j-1]]<dep[f[i+pw[j-1]][j-1]]?f[i][j-1]:f[i+pw[j-1]][j-1];
 31             }
 32         }
 33     }
 34     ll ask(ll l,ll r){
 35         l=fir[l],r=fir[r];
 36         if(l>r)swap(l,r);
 37         ll k=L[r-l+1];
 38         return dep[f[l][k]]<dep[f[r-pw[k]+1][k]]?f[l][k]:f[r-pw[k]+1][k];
 39     }
 40     ll dis(ll u,ll v){
 41         return dep[u]+dep[v]-2*dep[ask(u,v)];
 42     }
 43     void solve(){
 44         n=read(),m=read();
 45         for(ll i=1,u,v,w;i<n;++i){
 46             u=read(),v=read(),w=read();
 47             e[++num]=(P){v,head[u],w};head[u]=num;
 48             e[++num]=(P){u,head[v],w};head[v]=num;
 49         }
 50         dfs(1,0,0);RMQ();
 51     }
 52 }s;
 53 struct Divide{
 54     ll num,size,minn,rt,head[M],siz[M],f[M],sum[M],dis1[M],dis2[M];
 55     bool vis[M];
 56     P e[M<<1];
 57     void add(ll u,ll v,ll w){
 58         e[++num]=(P){v,head[u],w};head[u]=num;
 59     }
 60     void getrt(ll u,ll fa){
 61         ll ma=0;siz[u]=1;
 62         for(ll i=s.head[u];i;i=s.e[i].ne){
 63             ll v=s.e[i].to;
 64             if(v!=fa&&!vis[v]){
 65                 getrt(v,u);
 66                 siz[u]+=siz[v];
 67                 ma=max(ma,siz[v]);
 68             }
 69         }
 70         ma=max(ma,size-siz[u]);
 71         if(ma<minn){minn=ma,rt=u;}
 72     }
 73     void work(ll u){
 74         vis[u]=1;
 75         for(ll i=s.head[u];i;i=s.e[i].ne){
 76             ll v=s.e[i].to;if(vis[v])continue;
 77             minn=1e12;
 78             size=siz[v];getrt(v,0);
 79             add(u,rt,v);f[rt]=u;
 80             work(rt);
 81         }
 82     }
 83     void update(ll u,ll v){
 84         sum[u]+=v;
 85         for(ll i=u;f[i];i=f[i]){
 86             ll dist=s.dis(u,f[i]);
 87             dis1[f[i]]+=dist*v;
 88             dis2[i]+=dist*v;
 89             sum[f[i]]+=v;
 90         }
 91     }
 92     ll calc(ll u){
 93         ll ans=dis1[u];
 94         for(ll i=u;f[i];i=f[i]){
 95             ll dist=s.dis(f[i],u);
 96             ans+=dis1[f[i]]-dis2[i];
 97             ans+=dist*(sum[f[i]]-sum[i]);
 98         }
 99         return ans;
100     }
101     ll query(ll u){
102         ll ans=calc(u);
103         for(ll i=head[u];i;i=e[i].ne){
104             ll tmp=calc(e[i].w);
105             ll v=e[i].to;
106             if(tmp<ans)return query(v);
107         }
108         return ans;
109     }
110     void solve(){
111         minn=1e12;size=n;getrt(1,0);
112         ll la=rt;work(rt);
113         for(ll i=1,u,v;i<=m;++i){
114             u=read(),v=read();
115             update(u,v);
116             printf("%lld\n",query(la));
117         }
118     }
119 }t;
120 int main(){
121     s.solve();
122     t.solve();
123     return 0;
124 }
View Code

 

posted @ 2018-11-15 22:39  sjie  阅读(95)  评论(0编辑  收藏