【BZOJ3697】采药人的路径(点分治)
题意:采药人的药田是一个树状结构,每条路径上都种植着同种药材。
采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。
n<=100000
思路:RYZ作业
From hzwer:
来自出题人hta的题解。。
本题可以考虑树的点分治。问题就变成求过根满足条件的路径数。
路径上的休息站一定是在起点到根的路径上,或者根到终点的路径上。
如何判断一条从根出发的路径是否包含休息站?只要在dfs中记录下这条路径的和x,同时用个标志数组判断这条路径是否存在前缀和为x的节点。
这样我们枚举根节点的每个子树。用f[i][0…1],g[i][0…1]分别表示前面几个子树以及当前子树和为i的路径数目,0和1用于区分路径上是否存在前缀和为i的节点。那么当前子树的贡献就是f[0][0] * g[0][0] + Σf [i][0] * g [-i][1] + f[i][1] * g[-i][0] + f[i][1] * g[-i][1],其中i的范围[-d,d],d为当前子树的深度。
1 var head,vet,next,len,d,dis,son,flag,dep:array[1..210000]of longint; 2 c:array[0..110000]of longint; 3 b:array[-100000..100000]of longint; 4 f,g:array[-100000..100000,0..1]of int64; 5 n,m,i,x,y,z,tot,sum,root,mxdep:longint; 6 ans:int64; 7 8 procedure add(a,b,c:longint); 9 begin 10 inc(tot); 11 next[tot]:=head[a]; 12 vet[tot]:=b; 13 len[tot]:=c; 14 head[a]:=tot; 15 end; 16 17 function max(x,y:longint):longint; 18 begin 19 if x>y then exit(x); 20 exit(y); 21 end; 22 23 procedure getroot(u,fa:longint); 24 var e,v:longint; 25 begin 26 son[u]:=1; c[u]:=0; 27 e:=head[u]; 28 while e<>0 do 29 begin 30 v:=vet[e]; 31 if (v<>fa)and(flag[v]=0) then 32 begin 33 getroot(v,u); 34 son[u]:=son[u]+son[v]; 35 c[u]:=max(c[u],son[v]); 36 end; 37 e:=next[e]; 38 end; 39 c[u]:=max(c[u],sum-c[u]); 40 if c[u]<c[root] then root:=u; 41 end; 42 43 procedure dfs(u,fa:longint); 44 var e,v:longint; 45 begin 46 mxdep:=max(mxdep,dep[u]); 47 if b[dis[u]]>0 then inc(f[dis[u],1]) 48 else inc(f[dis[u],0]); 49 inc(b[dis[u]]); 50 e:=head[u]; 51 while e<>0 do 52 begin 53 v:=vet[e]; 54 if (v<>fa)and(flag[v]=0) then 55 begin 56 dep[v]:=dep[u]+1; 57 dis[v]:=dis[u]+len[e]; 58 dfs(v,u); 59 end; 60 e:=next[e]; 61 end; 62 dec(b[dis[u]]); 63 end; 64 65 procedure solve(u:longint); 66 var e,v,i,mx:longint; 67 begin 68 mx:=0; 69 flag[u]:=1; g[0,0]:=1; 70 e:=head[u]; 71 while e<>0 do 72 begin 73 v:=vet[e]; 74 if flag[v]=0 then 75 begin 76 dis[v]:=len[e]; 77 dep[v]:=1; mxdep:=1; 78 dfs(v,u); 79 mx:=max(mx,mxdep); 80 ans:=ans+(g[0,0]-1)*f[0,0]; 81 for i:=-mxdep to mxdep do 82 ans:=ans+g[-i,1]*f[i,1]+g[-i,0]*f[i,1]+g[-i,1]*f[i,0]; 83 for i:=-mxdep to mxdep do 84 begin 85 g[i,0]:=g[i,0]+f[i,0]; 86 g[i,1]:=g[i,1]+f[i,1]; 87 f[i,0]:=0; f[i,1]:=0; 88 end; 89 end; 90 e:=next[e]; 91 end; 92 for i:=-mx to mx do 93 begin 94 g[i,0]:=0; g[i,1]:=0; 95 end; 96 e:=head[u]; 97 while e<>0 do 98 begin 99 v:=vet[e]; 100 if flag[v]=0 then 101 begin 102 sum:=son[v]; root:=0; 103 getroot(v,0); 104 solve(root); 105 end; 106 e:=next[e]; 107 end; 108 end; 109 110 begin 111 assign(input,'bzoj3697.in'); reset(input); 112 assign(output,'bzoj3697.out'); rewrite(output); 113 readln(n); 114 for i:=1 to n-1 do 115 begin 116 readln(x,y,z); 117 if z=0 then z:=-1; 118 add(x,y,z); 119 add(y,x,z); 120 end; 121 root:=0; sum:=n; c[0]:=n; 122 getroot(1,0); 123 solve(root); 124 writeln(ans); 125 close(input); 126 close(output); 127 end.
null