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

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 }

 

posted @ 2018-12-21 23:07  Unstoppable728  阅读(185)  评论(0编辑  收藏  举报