POj 1703 Find them, Catch them(关系并查集)

题目: 戳我

题意:城市中有两个社会团伙

已知有n个人:编号为1~n,和m个信息

对于每个信息,D a b表明a和b属于不同的团伙,并且信息不会相互矛盾;A a b表示讯问a和b的关系,

要求依次回答每个讯问,回答形式如下:

Not sure yet.       //a和b的关系不确定

In different gans.  //a和b属于不同的团伙

In the same gang. //a和b属于同一个团伙

回顾并查集的合并操作:我们总是将同类的集合进行合并,但此题给出的却是不同类的两个元素。

抓住关键,城市的团伙只有两个,这个信息告诉我们:如果a和b不同类,b和c不同类,那么a和c必然属于一个团伙。

更一般的,如果我们把编号看做顶点,关系看做连边。那么,如果顶点a,b之间的路径包含奇数条边,那么a与b属于不同的团伙,如果a,b之间的路径包含偶数条边,那么a与b属于同一个团伙。

我们能够很容易的计算出元素x与根节点的“距离”(即路径上经过的边数)dis[x]。类似的,对于与x同属一个集合的任意元素y,我们也可以计算出y与根节点的“距离”dis[y]。那么,x与y的“距离”便可以用dis[x]+dis[y]表示。(注意,我们只关心“距离”的奇偶性,并不关心“距离”是否是最短的)

代码:

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <cctype>

#include <cmath>

#include <algorithm>

#include <vector>

#include <queue>

#include <stack>

#include <map>



using namespace std;



const int inf = 0x3f;

const int INF = 0x3f3f3f3f;

const int maxn = 1e5+5;



int bleg[maxn], dis[maxn], n, q;



int find(int x)

{

    int y = x, cnt = 0;

    while(y != bleg[y])

    {

        cnt += dis[y];

        y = bleg[y];

    }

    while(x != bleg[x])

    {

        int px = bleg[x], tmp = dis[x];

        dis[x] = cnt;

        bleg[x] = y;

        cnt -= tmp;

        x = px;

    }

    return y;

}



void Union(int a, int b)

{

    int pa = find(a), pb = find(b);

    if(pa == pb) return;

    dis[pa] = dis[a] + dis[b] + 1;

    bleg[pa] = pb;

}



void Init()

{

    for(int i = 0; i <= n; i++)

    {

        bleg[i] = i; dis[i] = 0;

    }

}

int main()

{

    int T;

    scanf("%d", &T);

    while(T--)

    {

        scanf("%d %d", &n, &q);

        Init();

        while(q--)

        {

            int x, y;

            char op;

            scanf(" %c %d %d", &op, &x, &y);

            if(op == 'A')

            {

                int pa = find(x), pb = find(y);

                if(pa != pb)

                {

                    puts("Not sure yet.");

                }

                else if((dis[x] + dis[y]) % 2 != 0)

                {

                    puts("In different gangs.");

                    //printf("%d %d\n", dis[x], dis[y]);

                }

                else 

                {

                    puts("In the same gang.");

                }

            }

            else 

            {

                Union(x, y);

            }

        }

    }

    return 0;

}

  

你可能感兴趣的:(catch)