POJ 1703 Find them, Catch them(并查集,向量偏移)

http://poj.org/problem?id=1703

题目大意:有一些黑帮的人分为两派,然后给出一些语句,D代表两个人在不同的帮派里,A代表输出两人的关系(不确定,在一个帮派里或不在一个帮派里)。做之前就知道这题是并查集的题目但是还是没什么思路,看题解也没看明白,后来看一位大牛讲解向量偏移的博客才明白了一点http://hi.baidu.com/tomspirit/item/d1f2a19b2aaf36d27a7f0158,向量偏移的思想这里也不赘述了,就是把关系的转移用类似向量的方式计算,维护一个off数组代表第x个元素与根节点关系,0表示属于同一个帮派,1表示不在一个帮派,在添加一组新的关系时,除了并查集的常规更新,还要更新一下off的值,详见代码。

#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
int pa[100005];
int off[100005];
char str[2];
int find(int k)
{
    if(pa[k]==k)
        return k;
    int temp=pa[k];     //记录k原来的父节点
    pa[k]=find(temp);   //并查集的常规更新
    off[k]=(off[k]-off[temp]+2)%2;   //网上很多代码都不是这么写的,不过我觉得这样写更容易理解,而且还要快一些
    //off[k]表示k节点原来的根节点到k的偏移量,off[temp]表示根节点到k原来的父节点的偏移量,我们要的off的值应该是k与其父节点之间的关系根据向量相减的原理,即得上式
    return pa[k];
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            pa[i]=i;
            off[i]=0;
        }
        for(int i=0;i<m;i++)
        {
            int x,y;
            scanf("%s%d%d",str,&x,&y);
            int pax=find(x);
            int pay=find(y);
            if(str[0]=='D')
            {
                if(pax!=pay)
                {
                    pa[pay]=pax;
                    off[pay]=(off[x]+1-off[y])%2;     //off表示pax到pay的偏移量,即为pax到x的偏移量+x到y+y到pay
                }
            }
            else if(str[0]=='A')
            {
                if(pax==pay)
                {
                    if(off[x]==off[y])
                    {
                        puts("In the same gang.");
                    }
                    else puts("In different gangs.");
                }
                else puts("Not sure yet.");
            }
        }
    }
}


你可能感兴趣的:(POJ 1703 Find them, Catch them(并查集,向量偏移))