其实这道题其实可以转化为这样一个问题
给定n-1对点,将这两点x,y间简单路径上的点(包括起点终点)权值+1
(最后再把除了起点外的点的权值-1,注意终点没糖吃)
求每个点的权值
首先想到的是先找LCA然后暴力的对权值加,显然这样效率不够好
想到了树状数组完成区间修改和单点求值,是先将[l,r]中a[l]++,然后a[r+1]--;
这样就避免了对每个数都修改;
以此类推,我们可以假定路径使x-->root-->y上的点+1,
这样每个点的权值即为其所在子树和
设lca(x,y)=z 同样的道理,我们只要对a[x]++,a[y]++,然后对a[z]--,a[fa[z]]--
因为每个点的权值即为其所在子树和,所以只有x-->y的简单路径上的点权值+1了
这样的话我们可以做一遍LCA-tarjan就可以搞出来了(当然也可以再单独扫一遍)
1 type node=record 2 po,next:longint; 3 can:boolean; 4 end; 5 6 var a,q:array[0..600010] of node; 7 fa,f,p,w,ans,g:array[0..300010] of longint; 8 v:array[0..300010] of boolean; 9 st,i,j,n,m,x,y,t:longint; 10 11 function getf(x:longint):longint; 12 begin 13 if fa[x]<>x then fa[x]:=getf(fa[x]); 14 exit(fa[x]); 15 end; 16 17 procedure addq(x,y:longint); 18 begin 19 inc(m); 20 q[m].po:=y; 21 q[m].next:=w[x]; 22 w[x]:=m; 23 end; 24 25 procedure add(x,y:longint); 26 begin 27 inc(t); 28 a[t].po:=y; 29 a[t].next:=p[x]; 30 p[x]:=t; 31 end; 32 33 procedure tarjan(x:longint); 34 var i,y,z:longint; 35 begin 36 i:=p[x]; 37 v[x]:=true; 38 while i<>0 do 39 begin 40 y:=a[i].po; 41 if not v[y] then 42 begin 43 f[y]:=x; 44 tarjan(y); 45 fa[y]:=x; 46 end; 47 i:=a[i].next; 48 end; 49 i:=w[x]; 50 while i<>-1 do 51 begin 52 y:=q[i].po; 53 if v[y] and not q[i].can then 54 begin 55 z:=getf(y); 56 q[i].can:=true; 57 q[i xor 1].can:=true; 58 inc(g[z]); 59 inc(g[f[z]]); 60 end; 61 i:=q[i].next; 62 end; 63 ans[x]:=ans[x]-g[x]; 64 ans[f[x]]:=ans[f[x]]+ans[x];//做到这已经说明x的子树已经被访问完了,x的权值已经确定,直接加即可,不需要再dfs一遍 65 end; 66 67 begin 68 m:=-1; 69 fillchar(w,sizeof(w),255); 70 readln(n); 71 read(x); 72 st:=x; 73 ans[x]:=1; 74 for i:=1 to n-1 do 75 begin 76 read(y); 77 addq(x,y); 78 addq(y,x); 79 inc(ans[y]); 80 if i<>n-1 then inc(ans[y]); 81 x:=y; 82 end; 83 for i:=1 to n-1 do 84 begin 85 readln(x,y); 86 add(x,y); 87 add(y,x); 88 end; 89 for i:=1 to n do 90 fa[i]:=i; 91 92 tarjan(1); 93 for i:=1 to n do 94 begin 95 if i<>st then dec(ans[i]); 96 writeln(ans[i]); 97 end; 98 end.