Find them, Catch them(带权值的并查集)

Find them, Catch them
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 44642 Accepted: 13751

Description

The police office in Tadu City decides to say ends to the chaos, as launch actions to root up the TWO gangs in the city, Gang Dragon and Gang Snake. However, the police first needs to identify which gang a criminal belongs to. The present question is, given two criminals; do they belong to a same clan? You must give your judgment based on incomplete information. (Since the gangsters are always acting secretly.) 

Assume N (N <= 10^5) criminals are currently in Tadu City, numbered from 1 to N. And of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. You will be given M (M <= 10^5) messages in sequence, which are in the following two kinds: 

1. D [a] [b] 
where [a] and [b] are the numbers of two criminals, and they belong to different gangs. 

2. A [a] [b] 
where [a] and [b] are the numbers of two criminals. This requires you to decide whether a and b belong to a same gang. 

Input

The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. Each test case begins with a line with two integers N and M, followed by M lines each containing one message as described above.

Output

For each message "A [a] [b]" in each case, your program should give the judgment based on the information got before. The answers might be one of "In the same gang.", "In different gangs." and "Not sure yet."

Sample Input

1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4

Sample Output

Not sure yet.
In different gangs.
In the same gang.

Source


题意:
就是有两个帮派,岗龙和岗蛇帮,现在就是判断是不是属于同一个帮派
T 代表几组测试数据;
N代表有多少个帮派; 
M代表接下来几行询问
-----
A 1 2 //询问1和2是否属于同一个帮派-----输出Not sure yet.
D 1 2 //表示1和2不属于同一个帮派
A 1 2 //询问1和2是否属于同一个帮派-----输出In different gangs.  
D 2 4 //表示2和4不属于同一个帮派
A 1 4 //询问1和4是否属于同一个帮派-----输出In the same gangs.
上面的D是累加的,也就是每次的出现都是保留下来的,没有覆盖更新。

/*并查集的集合是以能否确定关系来分的,而不是以属于同一个帮派或不同帮派来分的
这类题只需建立一个并查集,然后维护每个结点和他的根结点之间的关系属性即可
如果2个点不在同一个并查集中,那么这2个点无法确定关系
在同一个并查集中的每个点,都能确定集合中的相互关系
定义一个数组c表示两个派别,0和1,初始化为0。*/

第一步:
首先确定用0、1分别标记某一个节点和树根的同、异帮派关系
第二步:
可以先认为每个节点都是树根且都是与自身同帮派,据此初始化标记变量
第三步:
对每组输入数据进行处理,若两个节点的根结点不同,若输入A操作,则无法确定二者的帮派是否相同;
若为D操作,则合并两个节点所在的树且更新节点的关系;
若两个节点的根结点相同,则根据这两个节点的与根结点的关系来判断这两个节点的关系。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
int f[110000],c[110000];
int find(int x)
{
    if(f[x]==x)
        return x;
    int t=f[x];//先将当前结点x的父亲保存下来
    f[x]=find(f[x]);//递归找父亲顺便路径压缩,这时候f[x]存放的就是这颗树的根了
    c[x]=(c[x]+c[t])%2;//通过这条递推式在路径压缩的时候更新状态
    return f[x];//返回根
}
int make(char ch,int a,int b)
{
    int f1=find(a);
    int f2=find(b);
    if(f1!=f2)
    {
        if(ch=='A')
            return 0;
        f[f1]=f2;
        if((c[a]+c[b])%2==0)//通过a和b的c关系来更新a根结点的c
            c[f1]=1;
    }
    else
    {
        if(ch=='A')
        {
            if(c[a]!=c[b])  return 1;//当前的两个结点如果不在同一颗树上,就无法判定他们是否属相同帮派
            if(c[a]==c[b])  return 2;
        }
    }
    if(ch=='D')
        return 3;
}

int main()
{
    int ca,i,n,m;
    scanf("%d",&ca);
    while(ca--)
    {
        scanf("%d%d",&n,&m);
        getchar();
        for(i=1;i<=n;i++)//定义一个数组表示两个派别,0和1,初始化为0
        {
            f[i]=i;
            c[i]=0;
        }
        char ch;
        int a,b;
        for(i=1;i<=m;i++)
        {
            scanf("%c%d%d",&ch,&a,&b);
            getchar();
            int t=make(ch,a,b);
            if(t==0)
                printf("Not sure yet.\n");
            else if(t==1)
                printf("In different gangs.\n");
            else  if(t==2)
                printf("In the same gang.\n");
            else
                continue;
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
并查集(Weighted Union-Find)是一种常用的数据结构,用于解决动态连通性问题。它支持两个主要操作:合并(Union)和查找(Find)。 以下是一个使用Python实现的并查集示例代码: ```python class WeightedUnionFind: def __init__(self, n): self.parent = list(range(n)) self.size = [1] * n self.weight = [0] * n def find(self, x): if self.parent[x] != x: self.compress_path(x) return self.parent[x] def union(self, x, y, w): root_x = self.find(x) root_y = self.find(y) if root_x == root_y: return if self.size[root_x] < self.size[root_y]: self.parent[root_x] = root_y self.weight[root_x] = w - self.weight[x] + self.weight[y] self.size[root_y] += self.size[root_x] else: self.parent[root_y] = root_x self.weight[root_y] = -w + self.weight[x] - self.weight[y] self.size[root_x] += self.size[root_y] def compress_path(self, x): if self.parent[x] != x: self.compress_path(self.parent[x]) self.weight[x] += self.weight[self.parent[x]] self.parent[x] = self.parent[self.parent[x]] def get_weight(self, x): root = self.find(x) return self.weight[x] - self.weight[root] ``` 这个实现中,`parent`列表存储每个元素的父节点索引,`size`列表存储每个元素所在集合的大小,`weight`列表存储每个元素与其父节点的权值差。 `find()`方法用于查找元素所属的集合,并进行路径压缩优化。`union()`方法用于合并两个集合,并更新权值差。`compress_path()`方法用于路径压缩,加速后续的查找操作。`get_weight()`方法用于获取元素与其根节点的权值差。 并查集可以在解决一些算法问题中起到很好的作用,例如最小生成树算法中的Kruskal算法。希望这个示例代码能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值