Find them, Catch them(种类并查集)POJ - 1703

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.

题意:在一个城市中有两个帮派,龙邦和蛇帮,警察决定铲除它们。
给你N,M两个值,表示有N个罪犯,以1-N作为编号,再有M行,以D开头表示a,b是不同帮派的,以A开头,表示询问a,b两个人的关系。
如果同一帮派,In the same gang.
如果不同帮派,In different gangs.
如果不知道关系,Not sure yet.

思路:很显然是用种类并查集,普通并查集是以朋友的朋友还是朋友的思路串在一起。而种类并查集是以敌人的敌人是朋友联系在一起。
我们开一个两倍的并查集。例如,假如我们要维护4个元素的并查集,我们改为开8个单位的空间:

如果1和2是不同帮派的,我们可以把(1+N,2),(1,2+N)连在一起。


 如果2和4又是不同帮派的,我们再把(2+N,4),(2,4+N)连在一起。

 这图又可以看出什么呢?从图可知(2,5)(2,8)是连在一起的,表示2和5是不同帮派的,2和8也是不同帮派的,则5和8是同一帮派的,1(5-N)和4(8-N)是同一帮派的。

基于以上思想,我们可以写出下面的代码。


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include <sstream>
#include<vector>
#include<cmath>    
#include<stack>
#include<time.h>
#include<ctime>
using namespace std;
#define inf 1<<30
#define eps 1e-7
#define LD long double
#define LL long long
#define maxn 1000000005
int pre[200009] = {};
int rootsearch(int root)
{
    int son;
    son = root;
    while (root != pre[root])//这个数不是领导,继续往下找
    {
        root = pre[root];
    }
    while (son != root)//路径压缩,把找到的下级数全部指向最高领导
    {
        int temp = pre[son];
        pre[son] = root;
        son = temp;
    }
    return root;//返回最高领导
}
int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        int N, M, a, b;
        char ch;    
        scanf("%d%d", &N, &M);
        getchar();
        for (int i = 1; i <= 2 * N; i++)//初始化一个两倍的数组
        {
            pre[i] = i;
        }
        while(M--)
        {
            scanf("%c %d %d", &ch, &a, &b);//用cin会超时,别问我怎么知道的。。。
            getchar();
            if (ch == 'D')
            {
                pre[rootsearch(a + N)] = rootsearch(b);//把a+N和b联系在一起
                pre[rootsearch(b + N)] = rootsearch(a);//把b+N和a联系在一起
            }
            else
            {
                if (rootsearch(a) == rootsearch(b)||rootsearch(a+N)==rootsearch(b+N))//如果a,b或a+N,b+N的根节点一致
                {
                    printf("In the same gang.\n");
                }
                else if (rootsearch(a) == rootsearch(b + N) || rootsearch(a + N) == rootsearch(b))//如果a,b+N或a+N,b的根节点一致
                {
                    printf("In different gangs.\n");
                }
                else//两个人没有任何关系
                {
                    printf("Not sure yet.\n");
                }
            }
        }
    }
}

 




 

posted @ 2020-06-05 15:23  夜灯长明  阅读(550)  评论(0编辑  收藏  举报