种类并查集(POJ 1703)

1703 -- Find them, Catch them

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

题目大意:有2个敌对帮派,输入D a b表示a,b在不同帮派,输入A a b表示询问a,b是否是在一个帮派。

题解:因为并查集中的元素均是有联系的,否则也不会被合并到当前集合中。那么我们就把这2个元素之间的关系量转化为一个偏移量,

假设
x->y 偏移量0时 x和y同帮派

x->y 偏移量1时 x和y不同帮派

不妨继续假设,x的当前集合根节点tx,y的当前集合根节点ty。

如果tx和ty不相同,那么我们把ty合并到tx上,并且更新deltx[ty]值(注意:deltx[i]表示i的当前集合根节点到i的偏移量!!!!)

此时 tx->ty = tx->x + x->y + y->ty,可能这一步就是所谓向量思维模式吧

上式进一步转化为:tx->ty = (deltx[x]+1-deltx[y])%2 = deltx[ty],(模2是保证偏移量取值始终在[0,1]间)

接下来把这个想法再运用到路径压缩中:

ffx   

|     \

fx      \

|         /

|     /

x     

路径压缩过程中会将fx的父亲变为x的父亲,所以要改变相对关系,即偏移量。

ffx->fx+fx->x=ffx->x;

转换成:delta[x]=(delta[fx]+delta[x])%2;

int find(int x)
{
  if(x==fa[x])
    return fa[x];
  int f=fa[x];
  fa[x]=find(fa[x]);
  delta[x]=(delta[x]+delta[f])&1; //这句和上句不能交换位置,delta[]的改变是随着路径压缩是fa[]的改变而改变
  return fa[x];
}

#include <stdio.h>
int n;
int fa[100001],delta[100001];    //deltx[i]表示i的当前集合根节点到i的偏移量
void init()
{
    int i;
    for(i=1;i<=n;i++)
    {
        fa[i]=i;
        delta[i]=0;
    }
}

int find(int x)
{ 
    if(x==fa[x])
        return fa[x]; 
    int f=fa[x]; 
    fa[x]=find(fa[x]); 
    delta[x]=(delta[x]+delta[f])&1;     //这句和上句不能交换位置,delta[]的改变是随着路径压缩是fa[]的改变而改变
    return fa[x]; 
}


void merge(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    {
        fa[fy]=fx;
        delta[fy]=(delta[x]+1-delta[y])&1;
    }
}
int main()
{
    int t,m,i,a,b;
    char ch;
    scanf("%d",&t);
    while(t--)
    {
    
        scanf("%d%d%*c",&n,&m);  //%*c替掉回车,ch吃回车,经常搞错,哎。。。
        init();
        for(i=1;i<=m;i++)
        {
            scanf("%c%d%d%*c",&ch,&a,&b);
            if(ch=='D')
                merge(a,b);
            if(ch=='A')
            {
                if(find(a)==find(b))
                {
                    if(delta[a]==delta[b])     //根节点到a和b的偏移量相同时,a和b必定为同一帮派。朋友的朋友是朋友,敌人的敌人也是朋友
                        printf("In the same gang.\n");
                    else
                        printf("In different gangs.\n");
                }
                else
                    printf("Not sure yet.\n");
            }

        }
        
        
    }
    return 0;
}
View Code

原文地址:https://www.cnblogs.com/chiry/p/3233459.html