杭电OJ tree(并查集)

本文讨论了树形结构及其与并查集的结合应用,通过实例展示了如何使用并查集解决寻找树中最近点的问题。文章深入介绍了算法实现细节及优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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、付费专栏及课程。

余额充值