51nod 1253 Kundu and Tree

来源:互联网 发布:微信模板消息 java 编辑:程序博客网 时间:2024/06/10 01:39

题目在这里

这是一道容斥好题啊(话说容斥好像都是好题,因为都不好想qwq)

题目要求有多少个三元组(a,b,c)满足两两之间的路径上有至少一条红边。

正难则反,用任意三个点的方案数-不合法的方案数也是答案。

呐 么问题就变成了求有多少个不合法的方案,这棵树上会有若干个全是黑边的块,用并查集维护。

设一个黑块的大小为size。

则不合法方案分三个点都在这个黑块中,两个点在黑块中两种。

所以就是per(size)+size*(size-1)/2*(n-size)

然后这道题就迎刃而解啦,用并查集维护在容斥就可以了~


#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <cstdlib>#define ll long long#define mod 1000000007#define N 50000+500using namespace std;int num,x,y,fa[N];ll n,ans,size[N],a[N];char st[15];inline int find(int x){if(x!=fa[x]) fa[x]=find(fa[x]);return fa[x];}ll per(ll x){return x*(x-1)*(x-2)/6;}int main(){scanf("%lld",&n);for(int i=1;i<=n;i++) fa[i]=i,size[i]=1;for(int i=1;i<n;i++){scanf("%d%d%s\n",&x,&y,st+1);if(st[1]=='b'){int fax=find(x),fay=find(y);if(fax != fay) size[fax]+=size[fay],fa[y]=x;}}for(int i=1;i<=n;i++)if(fa[i]==i) a[++num]=size[i],ans-=per(size[i]);ans+=per(n);for(int i=1;i<=num;i++) ans-=a[i]*(a[i]-1)/2*(n-a[i]);ans=ans-mod*(ans/mod);printf("%lld\n",ans);return 0;}


原创粉丝点击