①普通并查集:
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; }