题目大意:给定n个点和m条限制条件(a=b or a≠b),判断是否矛盾
题解:离散化后并查集判断。具体实现时扫描两遍,第一遍维护所有a=b,第二遍检查冲突
我的收获:学会了离(S)散(T)化(L)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=1000005;
int T,n,cnt,flag;
int a[M*2],opt[M],u[M],v[M],f[M*2];
int fid(int x){
return f[x]==x?x:f[x]=fid(f[x]);
}
void uniom(int x,int y){
int p=fid(x),q=fid(y);
if(p!=q) f[p]=q;
}
void lishan()
{
cnt=unique(a+1,a+1+cnt)-a-1;//要减1才行!!!
for(int i=1;i<=n;i++){//如果需要保存原值可以开一个新的数组记录
u[i]=lower_bound(a+1,a+1+cnt,u[i])-a;//离散编号1--cnt
v[i]=lower_bound(a+1,a+1+cnt,v[i])-a;
}
}
void dealt(){
for(int i=1;i<=cnt;i++) f[i]=i;
}
void solve_1()
{
for(int i=1;i<=n;i++)
if(opt[i]) uniom(u[i],v[i]);
}
int solve_2()
{
for(int i=1;i<=n;i++)//判断矛盾
if(!opt[i]) if(fid(u[i])==fid(v[i])) return flag=0;
}
void print()
{
if(flag) puts("YES");
else puts("NO");
}
void work()
{
lishan();
dealt();
solve_1();
solve_2();
print();
}
void init()
{
int x,y,z;
cnt=0;flag=1;
memset(f,0,sizeof(f));//多组数据!!!
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x,&y,&z);
a[++cnt]=x,a[++cnt]=y;//记录每个出现的元素
u[i]=x,v[i]=y,opt[i]=z;
}
sort(a+1,a+1+cnt);
}
int main()
{
cin>>T;
while(T--){
init();
work();
}
return 0;
}