Description

给n组操作,每组操作形式为x y p。

当p为1时,如果第x变量和第y个变量可以相等,则输出YES,并限制他们相等;否则输出NO,并忽略此次操作。

当p为0时,如果第x变量和第y个变量可以不相等,则输出YES,并限制他们不相等 ;否则输出NO,并忽略此次操作。

Solution

这是一道很经典的题目。
如果只有强制相同集合的话,那么这题是很简单的。
但是,强制不相等的情况怎么办?
我们考虑一下数据结构:
如果要强制x和y不在同一个集合里面,我们维护一个x的集合(用set维护),里面存的是与x不在同一个集合的数,但是因为要用到并查集合并,所以集合里存的是x在并查集树上的根(getfather(x))
询问k,l,x=getfather(k),y=getfather(l)
那么当p=0的时候,如果两个数在同一棵并查集中的话,那么肯定是NO了,否则是YES,然后更新一下x的集合和y的集合,以此来强制两个数不在用一个集合。
如果p=1的情况,那么如果x=y那么直接YES,如果x的集合里面有y的话,那么说明x和y之前强制不在一个集合,那么就是NO。然后x和y的集合(set)就需要按秩合并了,如果x.size()

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<set>
#include<map>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100007;
int i,j,k,l,t,n,m,ans,tot,x,y,f[maxn];
set<int>a[maxn];
map<int,int>b;
int gf(int x){
if(!f[x])return x;
f[x]=gf(f[x]);
return f[x];
}
int main(){
// freopen("fan.in","r",stdin);
// freopen("fan.out","w",stdout);
set<int>:: iterator o;
for(scanf("%d",&n);n;n--){
scanf("%d%d%d",&k,&l,&t);
if(!b[k])b[k]=++tot,k=tot;else k=b[k];
if(!b[l])b[l]=++tot,l=tot;else l=b[l];
x=gf(k),y=gf(l);
if(!t){
if(x==y)printf("NO\n");
else{
printf("YES\n");
a[x].insert(y);
a[y].insert(x);
}
}
else{
if(a[x].count(y))printf("NO\n");
else if(x!=y){
printf("YES\n");
if(a[x].size()>a[y].size())swap(x,y);
f[x]=y;
for(o=a[x].begin();o!=a[x].end();o++){
// a[x].erase(*o);
a[y].insert(*o);
a[*o].erase(x);
a[*o].insert(y);
}
}
else printf("YES\n");
}
}
}