3697: 采药人的路径

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

HINT

 

对于100%的数据,N ≤ 100,000。

 
 
第一次写点分治。。。
黄学长的题解:

来自出题人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 #include<iostream>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<string>
  8 #include<map>
  9 #include<queue>
 10 #include<vector>
 11 #include<set>
 12 #define inf 1000000000
 13 #define maxn 100005
 14 #define maxm 200005
 15 #define eps 1e-10
 16 #define ll long long
 17 #define for0(i,n) for(int i=0;i<=(n);i++)
 18 #define for1(i,n) for(int i=1;i<=(n);i++)
 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 22 using namespace std;
 23 int read(){
 24     int x=0,f=1;char ch=getchar();
 25     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 26     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 27     return x*f;
 28 }
 29 int n,tot,sum,rt,mxdeep;
 30 bool vis[maxm];
 31 int t[maxm],mx[maxn],fa[maxn],size[maxn],deep[maxn],d[maxn],head[maxn];
 32 ll ans,g[maxm][2],f[maxm][2];
 33 struct edge{
 34     int go,next,w;
 35 }e[maxm];
 36 void insert(int u,int v,int w){
 37     e[++tot].go=v;e[tot].next=head[u];head[u]=tot;e[tot].w=w;
 38     e[++tot].go=u;e[tot].next=head[v];head[v]=tot;e[tot].w=w;
 39 }
 40 void getroot(int x,int fa){
 41     size[x]=1;mx[x]=0;
 42     for4(i,x){
 43         if(y!=fa&&!vis[y]){
 44             getroot(y,x);
 45             size[x]+=size[y];
 46             mx[x]=max(mx[x],size[y]);
 47         }
 48     }
 49     mx[x]=max(mx[x],sum-size[x]);
 50     if(mx[x]<mx[rt])rt=x;
 51 }
 52 void dfs(int x,int fa){
 53     mxdeep=max(mxdeep,deep[x]);
 54     if(t[d[x]])f[d[x]][1]++;
 55     else f[d[x]][0]++;
 56     t[d[x]]++;
 57     for4(i,x){
 58         if(y!=fa&&!vis[y]){
 59             deep[y]=deep[x]+1;
 60             d[y]=d[x]+e[i].w;
 61             dfs(y,x);
 62         }
 63     }
 64     t[d[x]]--;
 65 }
 66 void cal(int x){
 67     int mx=0;
 68     vis[x]=1;g[n][0]=1;
 69     for4(i,x){
 70         if(!vis[y]){
 71             d[y]=n+e[i].w;
 72             deep[y]=1;
 73             mxdeep=1;dfs(y,0);mx=max(mx,mxdeep);
 74             ans+=(g[n][0]-1)*f[n][0];
 75             for(int j=-mxdeep;j<=mxdeep;j++)
 76                 ans+=g[n-j][1]*f[n+j][1]+g[n-j][0]*f[n+j][1]+g[n-j][1]*f[n+j][0];
 77             for(int j=n-mxdeep;j<=n+mxdeep;j++){
 78                 g[j][0]+=f[j][0];
 79                 g[j][1]+=f[j][1];
 80                 f[j][0]=f[j][1]=0;
 81             }
 82         }
 83     }
 84     for(int i=n-mx;i<=n+mx;i++)g[i][0]=g[i][1]=0;
 85     for4(i,x){
 86         if(!vis[y]){
 87             sum=size[y];
 88             rt=0;
 89             getroot(y,0);
 90             cal(rt);
 91         }
 92     }
 93 }
 94 int main(){
 95     //freopen("input.txt","r",stdin);
 96     //freopen("output.txt","w",stdout);
 97     n=read();
 98     for1(i,n-1){
 99         int u=read(),v=read(),w=read();
100         if(!w)w=-1;
101         insert(u,v,w);
102     }
103     sum=mx[0]=n;
104     getroot(1,0);
105     cal(rt);
106     printf("%lld",ans);
107     return 0;
108 }
View Code

 

posted @ 2016-04-03 23:21  HTWX  阅读(178)  评论(0编辑  收藏  举报