题目大意
现在给出一些约束满足问题,请分别对它们进行判定,使得所给的所有约束条件(全由 等于 或 不等于 组成)同时被满足.
题目分析
我们发现等号具有递推性质,即若一对数相等,那么与这一对数中其中一个相等的数与这一对数都相等;而不等号就没有这种限制. 那么我们可以考虑用并查集实现,用等号的条件建树,用不等号的条件判断(即把等号和不等号的条件预处理分离).
与此同时,由于数据范围较大( 2 ∗ 1 e 10 2*1e10 2∗1e10),而数据规模较小( 1 e 4 1e4 1e4),所以考虑使用离散化. 那么本题就完成了.
#include<bits/stdc++.h>
#define maxn 400010
using namespace std;
int n;
int x[maxn],y[maxn],z[maxn],cmb[maxn];
int fa[maxn];
set<int >s;
int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);}
inline void operate(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x[i],&y[i],&z[i]);
s.insert(x[i]),s.insert(y[i]);
}
set<int >::iterator it;
int T=0;
while(!s.empty()){
it=s.begin();
cmb[++T]=*s.begin();
s.erase(it);//这里用set实现了去重和排序
}
for(int i=1;i<=n;i++){
x[i]=lower_bound(cmb+1,cmb+T+1,x[i])-cmb;
y[i]=lower_bound(cmb+1,cmb+T+1,y[i])-cmb;
fa[x[i]]=x[i],fa[y[i]]=y[i];//查找原值和初始化并查集
}
for(int i=1;i<=n;i++){
if(z[i]==1&&find(x[i])!=find(y[i]))fa[find(x[i])]=find(y[i]);
}
for(int i=1;i<=n;i++){
if(z[i]==0){
if(find(x[i])==find(y[i])){printf("NO\n");return ;}//先通过等号建树,后通过不等号判断
}
}
printf("YES\n");
return ;
}
inline void init(){
memset(x,0,sizeof x);
memset(y,0,sizeof y);
memset(z,0,sizeof z);
memset(cmb,0,sizeof cmb);
memset(fa,0,sizeof fa);
s.clear();
}
int main(){
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++){
init();
operate();
}
return 0;
}
题后总结
离散化属于小的知识点,但务必掌握.