杭电OJ tree(并查集)

tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 386    Accepted Submission(s): 190


Problem Description
There is a tree(the tree is a connected graph which contains n points and n1 edges),the points are labeled from 1 to n ,which edge has a weight from 0 to 1,for every point i[1,n] ,you should find the number of the points which are closest to it,the clostest points can contain i itself.
 


Input
the first line contains a number T,means T test cases.

for each test case,the first line is a nubmer n ,means the number of the points,next n-1 lines,each line contains three numbers u,v,w ,which shows an edge and its weight.

T50,n105,u,v[1,n],w[0,1]
 


Output
for each test case,you need to print the answer to each point.

in consideration of the large output,imagine ansi is the answer to point i ,you only need to output, ans1 xor ans2 xor ans3.. ansn .
 


Sample Input
  
  
1 3 1 2 0 2 3 1
 


Sample Output
  
  
1 in the sample. $ans_1=2$ $ans_2=2$ $ans_3=1$ $2~xor~2~xor~1=1$,so you need to output 1.

连通路径,并查集应用。

bestcoder比赛的时候,一直以为0是表示没有路,而1表示有路,最近的当然是1的那条边咯~。然后就是经验不足带来的无限WA的后果。很忧伤,很忧伤。。。。。。。。。。

这里大概题意是这样的:0边权和1边权都表示有路,但是0当然比1近,所以我们这里只考虑0的路,并不考虑1的路,因为我们要找的是当前点能找到的近的点。如果我要从这个点向周围找点,因为0边权进,所以我会去放弃1边权的点。所以这里当边权为0的时候,连通两点,直接不考虑1的路。

        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            f[i]=i;
            j[i]=1;//集合数。
        }
        for(int i=0;i<n-1;i++)
        {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            if(c==0)
            merge(x,y);
        }

然后我们这里就要涉及一个找到点的个数的问题。我们这里用一个数组j表示。

 当连通两点的时候,一个集合的点的数量,给另一个集合。

int find(int x)
{
    return f[x]==x?x:(f[x] = find(f[x]));
}
void merge(int a,int b)
{
    int A,B;
    A=find(a);
    B=find(b);
    if(A!=B)
    {
        f[A]=B;//这里表示A集合给了B(也可能是点)
        j[B]+=j[A];//然后把A集合的数量也加到B上、
    }
}


然后最后每一个点都找到自己的祖宗,询问有多少个点距离自己都是0.然后每一个都xor一下就可以了~。

最后上完整的AC代码:

#include<stdio.h>
#include<string.h>
using namespace std;
int f[100010];
int j[100010];
int find(int x)
{
    return f[x]==x?x:(f[x] = find(f[x]));
}
void merge(int a,int b)
{
    int A,B;
    A=find(a);
    B=find(b);
    if(A!=B)
    {
        f[A]=B;
        j[B]+=j[A];
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            f[i]=i;
            j[i]=1;
        }
        for(int i=0;i<n-1;i++)
        {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            if(c==0)
            merge(x,y);
        }
        int output=j[find(1)];
        for(int i=2;i<=n;i++)
        {
            output^=j[find(i)];
        }
        printf("%d\n",output);
    }
}






























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值