poj 1182 食物链(DSU)

①普通并查集:

f[i]=i,表示i属于A

f[i]=i+n,表示i属于B

f[i]=i+2*n,表示i属于C

每次合并之前先进行判断

如果x和y属于同类,则需要判断(x,y+n)和(x,y+2*n)

如果x吃y,则需要判断(x,y)和(x+2*n,y)

②带权并查集:

每次合并压缩路径的时候, 模三取余,然后判断权值即可


附上普通并查集的代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

const int INF=0x3f3f3f3f;
const int maxn=50005;
int n,k;
int f[3*maxn];

void Make_Set(){
	int Max=3*n;
	for(int i=0;i<Max;i++){
		f[i]=i;
	}
}

int find(int x){
	return x==f[x]?x:f[x]=find(f[x]);
}

void Union(int x,int y){
	int rx=find(x);
	int ry=find(y);
	f[ry]=f[rx];
}

bool judge(int x,int y){
	return find(x)==find(y);
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);
#endif
	scanf("%d%d",&n,&k);
	Make_Set();
	int res=0;
	int op,x,y;
	while(k--){
		scanf("%d%d%d",&op,&x,&y);
		x--,y--;
		if(x<0||x>=n||y<0||y>=n) {res++;continue;}
		if(op==1){
			if(judge(x,y+n)||judge(x,y+2*n))
				res++;
			else{
				Union(x,y);
				Union(x+n,y+n);
				Union(x+2*n,y+2*n);
			}
		}
		else{
			if(judge(x,y)||judge(x,y+2*n))
				res++;
			else{
				Union(x,y+n);
				Union(x+n,y+2*n);
				Union(x+2*n,y);
			}
		}
	}
	printf("%d\n",res);
	return 0;
}


你可能感兴趣的:(poj 1182 食物链(DSU))