BZOJ3697: 采药人的路径(点分治)
Description
采药人的药田是一个树状结构,每条路径上都种植着同种药材。
采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。
Input
第1行包含一个整数N。
接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。
Output
输出符合采药人要求的路径数目。
Sample Input
7
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
Sample Output
1
解题思路:
点分治要求在寻找到一条链时统计答案与重心在链的哪个位置无关。而显然这道题如果枚举重心为中转站是错误的,因为一条链只被统计一次,而中心位置很可能是错误的,所以我们需要修正这一点,就是统计重心路径上可能出现的中心位置。
换句话说,开四个桶来记录,分别记录当前子树内可能出现的中转站(出现过的距离重复,在差分的意义下说明出现和为0的区间),另外一个就是之前子树的答案,每次更新完合并桶就好了。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 const int N=100010; 6 struct pnt{ 7 int hd; 8 int dis; 9 int wgt; 10 bool vis; 11 }p[N]; 12 struct ent{ 13 int twd; 14 int lst; 15 int vls; 16 }e[N<<1]; 17 lnt f[N<<1][2],g[N<<1][2]; 18 int has[N<<1]; 19 int n; 20 lnt top; 21 int cnt; 22 lnt ans; 23 int lim; 24 int size; 25 int root; 26 int maxsize; 27 void ade(int f,int t,int v) 28 { 29 cnt++; 30 e[cnt].twd=t; 31 e[cnt].lst=p[f].hd; 32 e[cnt].vls=v; 33 p[f].hd=cnt; 34 return ; 35 } 36 void grc_dfs(int x,int f) 37 { 38 p[x].wgt=1; 39 int maxs=-1; 40 for(int i=p[x].hd;i;i=e[i].lst) 41 { 42 int to=e[i].twd; 43 if(to==f||p[to].vis) 44 continue; 45 grc_dfs(to,x); 46 p[x].wgt+=p[to].wgt; 47 if(p[to].wgt>maxs) 48 maxs=p[to].wgt; 49 } 50 if(maxs<size-p[x].wgt) 51 maxs=size-p[x].wgt; 52 if(maxs<maxsize) 53 { 54 maxsize=maxs; 55 root=x; 56 } 57 return ; 58 } 59 void ans_dfs(int x,int fa,int dep) 60 { 61 lim=std::max(lim,dep); 62 if(has[p[x].dis]) 63 f[p[x].dis][1]++; 64 else 65 f[p[x].dis][0]++; 66 has[p[x].dis]++; 67 for(int i=p[x].hd;i;i=e[i].lst) 68 { 69 int to=e[i].twd; 70 if(to==fa||p[to].vis) 71 continue; 72 p[to].dis=p[x].dis+e[i].vls; 73 ans_dfs(to,x,dep+1); 74 } 75 has[p[x].dis]--; 76 return ; 77 } 78 void bin_dfs(int x) 79 { 80 int maxd=0; 81 p[x].vis=true; 82 g[n][0]=1; 83 for(int i=p[x].hd;i;i=e[i].lst) 84 { 85 int to=e[i].twd; 86 if(p[to].vis) 87 continue; 88 p[to].dis=n+e[i].vls; 89 lim=1; 90 ans_dfs(to,to,1); 91 maxd=std::max(maxd,lim); 92 ans+=f[n][0]*(g[n][0]-1); 93 for(int j=-lim;j<=lim;j++) 94 ans+=g[n-j][1]*f[n+j][1]+g[n-j][1]*f[n+j][0]+g[n-j][0]*f[n+j][1]; 95 for(int j=n-lim;j<=n+lim;j++) 96 { 97 g[j][0]+=f[j][0]; 98 g[j][1]+=f[j][1]; 99 f[j][0]=f[j][1]=0; 100 } 101 } 102 for(int i=n-maxd;i<=n+maxd;i++) 103 g[i][0]=g[i][1]=0; 104 for(int i=p[x].hd;i;i=e[i].lst) 105 { 106 int to=e[i].twd; 107 if(p[to].vis) 108 continue; 109 root=0; 110 size=p[to].wgt; 111 maxsize=0x3f3f3f3f; 112 grc_dfs(to,to); 113 bin_dfs(root); 114 } 115 return ; 116 } 117 int main() 118 { 119 scanf("%d",&n); 120 for(int i=1;i<n;i++) 121 { 122 int a,b,c; 123 scanf("%d%d%d",&a,&b,&c); 124 c=c*2-1; 125 ade(a,b,c); 126 ade(b,a,c); 127 } 128 root=0; 129 size=n; 130 maxsize=0x3f3f3f3f; 131 grc_dfs(1,1); 132 bin_dfs(root); 133 printf("%lld\n",ans); 134 return 0; 135 }