HDU 5606 tree(并查集)

来源:互联网 发布:mac 打开隐藏的文件夹 编辑:程序博客网 时间:2024/05/17 00:03

Description
有一个树(n个点, n-1条边的联通图),点标号从1~n,树的边权是0或1.求离每个点最近的点个数(包括自己)
Input
第一行一个数字T,表示T组数据.
对于每组数据,第一行是一个n,表示点个数,接下来n-1行,每行三个整数u,v,w表示一条边连接的两个点和边权.
T=50,1≤n≤100000,0≤w≤1.
Output
对于每组数据,输出答案,考虑到输出规模过大,设ans​i表示第i个点的答案.你只需输出ansi的异或和即可
Sample Input
1
3
1 2 0
2 3 1
Sample Output
1
Solution
并查集,初始时每个点表示一个集合,如果两个点之间边权为0则将这两个点所在集合合并,最后得到的就是若干个内部点间距离为0的集合,统计每个集合内点的数量num[i],那么第i个集合中所有点的答案就都是cnt[i],由于只输出答案的异或和,所以只对有奇数个点的集合统计答案即可,时间复杂度O(n)
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;#define maxn 111111int T,n,ans,fa[maxn],num[maxn];void init(int n){    for(int i=1;i<=n;i++)        fa[i]=i,num[i]=1;}int find(int x){    if(fa[x]==x)return x;    return fa[x]=find(fa[x]);}void unit(int x,int y){    x=find(x),y=find(y);    if(x==y)return ;    fa[y]=x;    num[x]+=num[y];}int main(){    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        init(n);        for(int i=1;i<n;i++)        {            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            if(!w)unit(u,v);        }        ans=0;        for(int i=1;i<=n;i++)            if(fa[i]==i&&(num[i]&1))                ans^=num[i];        printf("%d\n",ans);    }    return 0;}
0 0