拓展并查集

拓展并查集

image-20220705142921883

这段话应该是比较关键的,拓展域并查集是用来解决有排斥关系的题。

其思路就是疯狂扩大倍数,每增加一倍就保存一个·对立的关系。然后合并时要注意用可要把对立关系合并起来,

举个列子吧。就比如说洛谷p2204这个题,他就是有三个关系,食物,天敌。你每次合并不仅要把自己合并,你还要把食物和天敌合并。然后我是你的食物就是必须把我的食物当作你的天敌。你的天敌当做我对食物。

#include<bits/stdc++.h>
using namespace std;

#define fl(i,x,y) for(int i=x;i<=y;i++)
#define fh(i,x,y) for(int i=x;i>=y;i--)
#define ll long long
#define pb push_back

const int N=5e4+10;
int n,k,fa[N*3];
int find(int x){
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}
void merge(int x,int y){
x=find(x),y=find(y);
if(x==y) return;
fa[x]=y;
}
int main(){
cin>>n>>k;
int ans=0;
fl(i,1,3*n) fa[i]=i;
fl(i,1,k){
int op,x,y;
cin>>op>>x>>y;
if(x>n||y>n||x<1||y<1){
ans++;
continue;
}
if(op==1){
           //xy是同类但是可没可能还么合并呢比如说刚给的时候,所以还是的根据前面给的来判断,不然初始数据fa[i]=i就会默认把两个视为不同的食物典型错误就是find(a)!=find(b),这个判断条件是错误的。
if(find(x+n)==find(y)||find(x)==find(y+n)){/
ans++;
continue;
}
else{
merge(x,y);
merge(x+n,y+n);
merge(x+2*n,y+2*n);
}
}
if(op==2){
if(x==y){
ans++;
continue;
}
if(find(x+2*n)==find(y)||find(x)==find(y)){//x的天敌是y或者x和y是同类
ans++;
continue;
}
else{
merge(x,y+2*n);
merge(x+n,y);
merge(x+2*n,y+n);
}
}
}
cout<<ans<<endl;
}
 

 

posted @ 2022-07-25 23:14  silky__player  阅读(44)  评论(0)    收藏  举报