Description
小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达。游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄,然后可以任意在地图的道路上行走,若走到某个村庄中有宝物,则视为找到该村庄内的宝物,直到找到所有宝物并返回到最初转移到的村庄为止。
小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。
为了简化问题,我们认为最开始时所有村庄内均没有宝物。
小B希望评测一下这个游戏的难度,因此他需要知道玩家找到所有宝物需要行走的最短路程。但是这个游戏中宝物经常变化,有时某个村庄中会突然出现宝物,有时某个村庄内的宝物会突然消失,因此小B需要不断地更新数据,但是小B太懒了,不愿意自己计算,因此他向你求助。
为了简化问题,我们认为最开始时所有村庄内均没有宝物。
Input
第一行,两个整数N、M,其中M为宝物的变动次数。
接下来的N-1行,每行三个整数x、y、z,表示村庄x、y之间有一条长度为z的道路。
接下来的M行,每行一个整数t,表示一个宝物变动的操作。若该操作前村庄t内没有宝物,则操作后村庄内有宝物;若该操作前村庄t内有宝物,则操作后村庄内没有宝物。
接下来的N-1行,每行三个整数x、y、z,表示村庄x、y之间有一条长度为z的道路。
接下来的M行,每行一个整数t,表示一个宝物变动的操作。若该操作前村庄t内没有宝物,则操作后村庄内有宝物;若该操作前村庄t内有宝物,则操作后村庄内没有宝物。
Output
M行,每行一个整数,其中第i行的整数表示第i次操作之后玩家找到所有宝物需要行走的最短路程。若只有一个村庄内有宝物,或者所有村庄内都没有宝物,则输出0。
Sample Input
4 5
1 2 30
2 3 50
2 4 60
2
3
4
2
1
Sample Output
0
100
220
220
280
Data Constraint
解法:
一个比较直观的想法是把有宝物点的虚树构出来,答案就是虚树中边的总长度*2。
但动态维护虚树比较麻烦。经过观察我们可以发现:只要出发点在虚树之中,那么答案就不会变,而且走的路径是一个环,即一个经过所有点的欧拉回路。
即我们把欧拉遍历(或dfn序)中相邻两点的距离加起来,再加上首尾距离,就是答案。
所以我们用一棵splay维护dfn序,复杂度O(MlogN)
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef long long ll; struct Tree{ int son[2],fa,key; }tr[200011]; ll f[100011],Ans,dep[100011]; int len[200022],next[200022],y[200022],g[100011],que[100011]; int fa[100011][17],dfn[100011],num[100011],th[100011],D[100011]; int n,m,tot,T,j,rs,x,z,q,i,tt,sum,dst,ls,root; bool pl; void star(int i,int j,int k) { tt++; next[tt]=g[i]; g[i]=tt; y[tt]=j; len[tt]=k; } void dfs(int x) { int j,k; dfn[x]=++T; num[T]=x; j=g[x]; while(j!=0){ k=y[j]; if(k!=fa[x][0]){ fa[k][0]=x; D[k]=D[x]+1; dep[k]=dep[x]+len[j]; dfs(k); } j=next[j]; } } int get(int x,int z) { int i,l,e; if(D[x]<D[z])swap(x,z); l=D[x]-D[z]; e=0; while(l){ if(l%2==1)x=fa[x][e]; l/=2; e++; } if(x==z)return x; for(i=16;i>=0;i--)if(fa[x][i]!=fa[z][i]){ x=fa[x][i]; z=fa[z][i]; } return fa[x][0]; } ll dis(int x,int z) { return dep[x]+dep[z]-2*dep[get(x,z)]; } void Find(int x,int z) { if(tr[x].key==z){ dst=x; return; } if(tr[x].key>z)Find(tr[x].son[0],z); else Find(tr[x].son[1],z); } void ins(int &x,int z,int ls) { if(x==0){ x=++tot; tr[x].fa=ls; tr[x].key=z; return; } if(tr[x].key>z)ins(tr[x].son[0],z,x); else ins(tr[x].son[1],z,x); } void rotate(int x) { int z,e; z=tr[x].fa; e=tr[z].son[1]==x; tr[z].son[e]=tr[x].son[e^1]; tr[tr[x].son[e^1]].fa=z; tr[x].son[e^1]=z; if(tr[z].fa!=0){ e=tr[tr[z].fa].son[1]==z; tr[tr[z].fa].son[e]=x; } tr[x].fa=tr[z].fa; tr[z].fa=x; } void splay(int x) { int nt,ft,e1,e2; while(tr[x].fa!=0){ if(tr[tr[x].fa].fa==0)rotate(x); else{ ft=tr[x].fa; nt=tr[ft].fa; e1=tr[ft].son[1]==x; e2=tr[nt].son[1]==ft; if(e1==e2)rotate(ft),rotate(x); else rotate(x),rotate(x); } } root=x; } int findlst(int x) { x=tr[x].son[0]; while(tr[x].son[1])x=tr[x].son[1]; return x; } int findnxt(int x) { x=tr[x].son[1]; while(tr[x].son[0])x=tr[x].son[0]; return x; } int findmax(int x) { while(tr[x].son[1])x=tr[x].son[1]; return tr[x].key; } int findmin(int x) { while(tr[x].son[0])x=tr[x].son[0]; return tr[x].key; } void del(int x) { Find(root,dfn[x]); splay(dst); ls=findlst(dst); if(!ls)ls=findmax(root); else ls=tr[ls].key; rs=findnxt(dst); if(!rs)rs=findmin(root); else rs=tr[rs].key; Ans=Ans-dis(num[ls],num[tr[dst].key])-dis(num[rs],num[tr[dst].key]); Ans+=dis(num[ls],num[rs]); if(findnxt(dst)==0){ root=tr[dst].son[0]; tr[root].fa=0; } else{ root=findnxt(dst); splay(root); if(tr[dst].son[0])tr[tr[dst].son[0]].fa=root; tr[root].son[0]=tr[dst].son[0]; } } void Work() { int i,l,r,x,j,k,lx,mx,mn; Ans=0; root=0; for(i=1;i<=m;i++){ scanf("%d",&x); lx=th[x]; th[x]^=1; if(th[x]==0)del(x); else{ ins(root,dfn[x],0); splay(tot); ls=findlst(tot); if(!ls)ls=findmax(root); else ls=tr[ls].key; rs=findnxt(tot); if(!rs)rs=findmin(root); else rs=tr[rs].key; Ans-=dis(num[ls],num[rs]); Ans+=dis(num[ls],x)+dis(x,num[rs]); } printf("%lld\n",Ans); } } int main() { scanf("%d%d",&n,&m); pl=true; for(i=1;i<n;i++){ scanf("%d%d%d",&x,&z,&q); star(x,z,q); star(z,x,q); } dfs(1); for(i=1;i<=16;i++) for(j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1]; Work(); }