您的位置:首页 > 其它

【BZOJ3697】采药人的路径(点分治)

2017-03-09 16:16 459 查看

题意:采药人的药田是一个树状结构,每条路径上都种植着同种药材。
采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。

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.

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: