【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.

 

posted on 2017-03-09 16:16  myx12345  阅读(237)  评论(0编辑  收藏  举报

导航