POJ1182--带权并查集

带权并查集就是除了维护一个fa数组以外,维护一个rank数组,有两层含义,一个是路径压缩时边的权值,,再一个是当前点与根节点的相对关系。这个题很明显考察的是

根节点与当前节点的一种相对关系,让rank【x】 = 0 ,1,2表示A,B,C三个种类的动物,在刚开始的时候,所有的动物的rank值都是0,表示还没有给他们安排关系,随

着语句的输入,1xy表示把x,y置为相同值,2xy表示rank【x】 + 1 = rank【y】,然而在这里并不是直接改变y的rank的值,而是改变y所在的根结点的rank值,因为一旦x,y确

立了关系,和y在一个集合内的动物都与x建立了关系,这样只有改变根节点的rank才能保证每一个动物的rank都会被更新到,因为在x所在的集合和y所在的集合没有建立关系

之前,x,y的关系可以是任意的。

如果输入1xy,首先看x,y是否在一个集合内,如果是那麽x,y之间是一种绝对的关系,可以通过rank【x】和rank【y】的大小来判断语句的正确性,如果不是那麽x,y之间就没有

确定的关系,那么这句话就是对的,修改rank【y】所在集合的根结点的rank值,

输入2xy时和输入1xy时同理。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
#define N 100005
#define lc rt<<1
#define rc rt<<1|1
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 5e4 + 10;

int n,k;
int d,x,y;
int fa[maxn];
int rank[maxn];

int find(int x)
{
    if(fa[x] == x)
    return x;
    int p = find(fa[x]);
    rank[x] = (rank[fa[x]] + rank[x])%3;
    return fa[x] = p;
}

int main()
{
     //freopen("in","r",stdin);
     int cnt = 0;
     scanf("%d%d",&n,&k);
     for(int i = 0; i < n; ++i) fa[i] = i;

     memset(rank,0,sizeof(rank));
     for(int i = 0; i < k; ++i)
     {
         scanf("%d%d%d",&d,&x,&y);
         if(x > n||y > n||(d == 2&&x == y)) {
             cnt++;continue;}
         int s1 = find(x),s2 = find(y);//求根节点
         if(d == 1){
             if(s1 == s2){
                 if(rank[x] != rank[y]) cnt++;
             }
             else {
                 rank[s2] = (rank[x] - rank[y] + 3)%3;//更新y的根结点,注意不要写错s2;
                 fa[s2] = s1;//建立x集合与y集合的关系;
             }
         }
         else if(d == 2)
         {
             if(s1 == s2) {
                 if((rank[x] + 1)%3 != rank[y]) cnt++;
             }
             else {
                 rank[s2] = (rank[x] + 1 - rank[y] + 3)%3;//同上
                 fa[s2] = s1;
             }
         }
         //printf("%d %d\n",i,cnt);
     }
     printf("%d\n",cnt);
}

 

你可能感兴趣的:(POJ1182--带权并查集)