[51nod1253]Kundu and Tree

  树包含N个点和N-1条边。树的边有2中颜色红色('r')和黑色('b')。给出这N-1条边的颜色,求有多少节点的三元组(a,b,c)满足:节点a到节点b、节点b到节点c、节点c到节点a的路径上,每条路径都至少有一条边是红色的。
  注意(a,b,c), (b,a,c)以及所有其他排列被认为是相同的三元组。输出结果对1000000007取余的结果。

 Input
  第1行:1个数N(1 <= N <= 50000)
  第2 - N行:每行2个数加一个颜色,表示边的起始点和结束的以及颜色。
 Output
  输出1个数,对应符合条件的3元组的数量。

 

 

  奇特的思路。。黑边没有什么用...就把黑边相连的合成一个联通块。

  只要选择的三个点在不同的联通块内就合法了...

  答案就变成 随便选三个点的方案数 - 三个点在同个联通块内的方案数 - 两个点在同个联通块内的方案数

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cmath>
 7 #include<cstdlib>
 8 #define ll long long
 9 #define ull unsigned long long
10 #define ui unsigned int
11 //#define d double
12 #define ld long double
13 const int maxn=50023,modd=1000000007;
14 int c[maxn][4],fa[maxn],sz[maxn];
15 int i,j,k,n,m;
16 
17 int ra,fh;char rx;
18 inline int read(){
19     rx=getchar(),ra=0,fh=1;
20     while(rx<'0'&&rx!='-')rx=getchar();
21     if(rx=='-')fh=-1,rx=getchar();
22     while(rx>='0')ra=ra*10+rx-48,rx=getchar();return ra*fh;
23 }
24 inline int getfa(int x){return fa[x]!=x?fa[x]=getfa(fa[x]):x;}
25 inline void MOD(int &x){if(x>=modd)x-=modd;}
26 inline void UPD(int &x){if(x<0)x+=modd;}
27 int main(){
28     n=read();
29     c[0][0]=1;register int i,j;
30     for(i=1;i<=n;i++){
31         c[i][0]=sz[i]=1,fa[i]=i;
32         for(j=1;j<=3;j++)MOD(c[i][j]=c[i-1][j-1]+c[i-1][j]);//,printf(" %d %d   c:%d\n",i,j,c[i][j]);
33     }
34     int x,y;
35     for(i=1;i<n;i++){
36         x=read(),y=read();
37         if(getchar()=='b')x=getfa(x),y=getfa(y),fa[x]=y,sz[y]+=sz[x];
38     }
39     int ans=c[n][3];
40     for(i=1;i<=n;i++)if(fa[i]==i)
41         UPD(ans-=(c[sz[i]][3]+1ll*(n-sz[i])*c[sz[i]][2])%modd);
42     printf("%d\n",ans);
43 }
View Code

 

posted @ 2016-10-11 18:50  czllgzmzl  阅读(272)  评论(0编辑  收藏  举报