Description
小Y盯上了最近发行的即时战略游戏——ResourceTransport。但在前往通关之路的道路上,一个小游戏挡住了小Y的步伐。“国家的本质是生产与收集资源”是整款游戏的核心理念,这个小游戏也不例外。简单的说,用户需要管理一个国家,使其繁荣富强。
一个国家含有N个城市,游戏开始时城市间没有任何道路。城市可以通过高速公路连接。为了减少建设费用,每对城市间最多存在一条路径。
小Y拥有极强的游戏天赋,很快就把所有城市的生产能力提到了满级,把高速公路的建设费用修改成了0。
悲剧的是,对于每个连通的城市群,都要把该城市群中的某个城市设立成资源集合处,小Y把这件事忘了;更悲剧的是,建造高速公路这件事,小Y也忘了。
可小Y是个完美主义者,他请来了你帮他设立资源集合处,自己负责建造高速公路。假设连通城市群中的某个城市i到该城市群的资源集合处最少需要经过Di条高速公路,那么总运输费用为Sigma(Di)。你需要在每个连通城市群中设立一个资源集合处,使得总费用最小。小Y有时会向你询问此时最小的总费用。
问题很简单,麻烦的是小Y会在你好不容易算出最小总费用时建造一条新的高速公路。由于每个连通的城市群只能有一个资源集合处,所以最小总费用又得重新计算,这可真是个苦差事……
Input
第一行两个整数N,M分别表示国家中的城市数与小Y的操作数。
接下来M行,每行可能为:
1.A x y:表示在城市x和城市y间建造一条高速公路,保证此操作出现N-1次;
2.Q:表示小Y询问此时的最小总费用。
Output
对于每个Q操作,单独输出一行一个整数Ans,表示所求的答案。
有一个结论是对树上任意一条边,在删去边得到的两棵子树中各取一个重心,它们在原树上的路径上会经过原树的至少一个重心
树链剖分+zkw线段树维护每个以重心为根的树上每个点的子树大小、子树中点的深度和,加边时启发式合并,重构较小的一棵树,考虑一步一步移动原有重心到新的重心,由于移动步数不超过较小的一棵树的大小,可以保证时间复杂度为$O(nlog^2n)$
#include<cstdio> #include<cstring> #include<algorithm> const int N=40007; int __; char buf[N*30],*ptr=buf; int _(){ int x=0; while(*ptr<48)++ptr; while(*ptr>47)x=x*10+*ptr++-48; return x; } int _o(){ while(*ptr<33)++ptr; return *ptr++; } int es[N*2],enx[N*2],e0[N],ep=2; int n,m,qs[N*2][2]; int dep[N],fa[N],sz[N],son[N],top[N],id[N],idp=0; void ae(int a,int b){ es[ep]=b;enx[ep]=e0[a];e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } void f1(int w,int pa){ dep[w]=dep[fa[w]=pa]+1; sz[w]=1; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=pa){ f1(u,w); sz[w]+=sz[u]; if(sz[u]>sz[son[w]])son[w]=u; } } } void f2(int w,int tp){ top[w]=tp; id[w]=++idp; if(son[w])f2(son[w],tp); for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=fa[w]&&u!=son[w])f2(u,u); } } int lca(int x,int y){ int a=top[x],b=top[y]; while(a!=b){ if(dep[a]>dep[b])x=fa[a],a=top[x]; else y=fa[b],b=top[y]; } return dep[x]<dep[y]?x:y; } int up(int x,int y){ int a=top[x],b=top[y]; while(a!=b){ y=fa[b]; if(x==y)return b; b=top[y]; } return son[x]; } int f[N],rt[N],siz[N],res[N],ans=0; int gf(int x){ while(x!=f[x])x=f[x]=f[f[x]]; return x; } int tr[133333][3],mx; #define A tr][0 #define B tr][1 #define C tr][2 int cnt=0; void getv(int x,int&v1,int&v2){ v1=v2=0; for(int w=x+mx;w;w>>=1){ v1+=w[A]; v2+=w[B]+w[C]*x; } } void setv(int x,int v1,int v2){ int a1,a2,w=mx+x; getv(x,a1,a2); w[A]+=v1-a1; w[B]+=v2-a2; } void adds(int l,int r,int a,int b,int c){ for(l+=mx-1,r+=mx+1;r-l!=1;l>>=1,r>>=1){ if(~l&1){ int w=l^1; w[A]+=a; w[B]+=b; w[C]+=c; } if(r&1){ int w=r^1; w[A]+=a; w[B]+=b; w[C]+=c; } } } void add(int x,int y,int v1,int v2){ int D1=dep[x]+dep[y]+1-dep[lca(x,y)]*2,D2=1; int a=top[x],b=top[y]; while(a!=b){ if(dep[a]>dep[b]){ adds(id[a],id[x],v1,v2+(D2+id[x])*v1,-v1); D2+=id[x]-id[a]+1; x=fa[a];a=top[x]; }else{ adds(id[b],id[y],v1,v2+(D1-id[y])*v1,v1); D1-=id[y]-id[b]+1; y=fa[b];b=top[y]; } } if(dep[x]>dep[y]){ adds(id[y],id[x],v1,v2+(D2+id[x])*v1,-v1); }else{ adds(id[x],id[y],v1,v2+(D1-id[y])*v1,v1); } } bool chk(int&w,int u){ int w1,w2,u1,u2; getv(id[w],w1,w2); getv(id[u],u1,u2); if(w2>u2+(w1-u1)+(w2-u2-u1)){ setv(id[w],w1-u1,w2-u2-u1); setv(id[u],w1,u2+(w1-u1)+(w2-u2-u1)); w=u; return 1; } return 0; } int sz1[N],ds1[N]; void dfs(int w,int pa){ sz1[w]=1;ds1[w]=0; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=pa){ dfs(u,w); sz1[w]+=sz1[u]; ds1[w]+=ds1[u]+sz1[u]; } } setv(id[w],sz1[w],ds1[w]); } void mg(int x,int y){ int a=gf(x),b=gf(y); if(siz[a]<siz[b])std::swap(a,b),std::swap(x,y); dfs(y,0); ae(x,y); add(x,rt[a],sz1[y],ds1[y]); f[b]=a; siz[a]+=siz[b]; ans-=res[a]+res[b]; int c=lca(rt[a],rt[b]),w=rt[a]; while(w!=c)if(!chk(w,fa[w]))goto o1; while(w!=rt[b])if(!chk(w,up(w,rt[b])))break; o1: rt[a]=w; getv(id[w],__,res[a]); ans+=res[a]; } int main(){ fread(buf,1,sizeof(buf),stdin)[buf]=0; n=_();m=_(); for(int i=1;i<=n;++i){ f[i]=rt[i]=i; siz[i]=1; } for(int i=1;i<=m;++i){ if(_o()=='A'){ qs[i][0]=_(); qs[i][1]=_(); ae(qs[i][0],qs[i][1]); }else qs[i][0]=-1; } f1(1,0);f2(1,1); ep=2; memset(e0,0,n+2<<2); for(mx=1;mx<=idp+4;mx<<=1); for(int i=1;i<=idp;++i)(mx+i)[A]=1; for(int i=1;i<=m;++i){ if(qs[i][0]==-1)printf("%d\n",ans); else mg(qs[i][0],qs[i][1]); } return 0; }