程序自动分析
Description
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:
假设
x1,x2,x3,…
代表程序中出现的变量,给定
n
个形如
例如,一个问题中的约束条件为:
x1=x2,x2=x3,x3=x4,x1≠x4
,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。
Input
输入文件的第
1
行包含
注意这些问题之间是相互独立的。
对于每个问题,包含若干行:
第
接下来
n
行,每行包括
Output
输出文件包括
t
行。
输出文件的第
Sample Input
2
2
1 2 1
1 2 0
2
1 2 1
2 1 1
Sample Output
NO
YES
Hint
在第一个问题中,约束条件为:
这两个约束条件互相矛盾,因此不可被同时满足。
在第二个问题中,约束条件为:
x1=x2,x2=x1
。
这两个约束条件是等价的,可以被同时满足。
1≤n≤1000000
1≤i,j≤1000000000
Solution
这个题目就是一个简单的并查集。
只不过因为变量太大,导致数组开不下。
因为
n
<script type="math/tex" id="MathJax-Element-417">n</script> 比较小,所以我们可以开一个数组将所有的变量存下来,用这些变量的下标来表示这些变量。
使这个数组有序,那么就可以用二分查找来查找每个变量。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int T,n,cnt,tot;
int to[1000010][3];
int in[2000010];
int data[2000010];
int fa[2000010];
int find(int x){
int tmp=x,pre;
while(tmp!=fa[tmp])tmp=fa[tmp];
while(x!=tmp){
pre=fa[x];
fa[x]=tmp;
x=pre;
}
return tmp;
}
void add(int x,int y){
fa[x]=y;
}
int search(int l,int r,int q){
while(l<=r){
int mid=(l+r)>>1;
if(data[mid]==q)return mid;
if(data[mid]<q)l=mid+1;
else r=mid-1;
}
}
int main(){
scanf("%d",&T);
while(T--){
cnt=tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&to[i][1],&to[i][2],&to[i][0]);
in[++cnt]=to[i][1];
in[++cnt]=to[i][2];
}
sort(in+1,in+cnt+1);
for(int i=1;i<=cnt;i++)if(in[i]!=in[i-1])data[++tot]=in[i];
for(int i=1;i<=tot;i++)fa[i]=i;
bool flag=true;
for(int i=1;i<=n;i++)if(to[i][0]){
int pos1=search(1,tot,to[i][1]),pos2=search(1,tot,to[i][2]);
int fa=find(pos1),fb=find(pos2);
add(fa,fb);
}
for(int i=1;i<=n;i++)if(!to[i][0]){
int pos1=search(1,tot,to[i][1]),pos2=search(1,tot,to[i][2]);
int fa=find(pos1),fb=find(pos2);
if(fa==fb){
printf("NO\n");
flag=false;
break;
}
}
if(flag)printf("YES\n");
}
return 0;
}