P1955 [NOI2015] 程序自动分析
题面
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设 \(x_1,x_2,x_3,\cdots\) 代表程序中出现的变量,给定 \(n\) 个形如 \(x_i=x_j\) 或 \(x_i\neq x_j\) 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:\(x_1=x_2,x_2=x_3,x_3=x_4,x_4\neq x_1\),这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。
【数据范围】
思路
可以用并查集维护。
如果相等,那么合并。如果不等,检查是否在一个集合中,如果在就是 NO
, 否则就是 YES
。
至于值域问题,可以考虑以下方案:
- 离散化
- 使用映射数据结构(如
std::map
,std::unordered_map
,__gnu_pbds::gp_hash_table
等)。
这里使用第二种。经过实验,只有 std::unordered_map
能过。其他都是 \(90\) 分(开了 \(\text{O2}\) )。
#include <bits/stdc++.h>
//#include <bits/extc++.h>
using namespace std;
//using namespace __gnu_pbds;
const int SIZE = 1e6+5;
int t,T;
struct query{
int i,j,e;
} querys[SIZE];
unordered_map<int,int> fa;
namespace IO{
const int SIZE=1<<21;
static char ibuf[SIZE],obuf[SIZE],*iS,*iT,*oS=obuf,*oT=oS+SIZE-1;
int qr;
char qu[55],c;
bool f;
#define getchar() (IO::iS==IO::iT?(IO::iT=(IO::iS=IO::ibuf)+fread(IO::ibuf,1,IO::SIZE,stdin),(IO::iS==IO::iT?EOF:*IO::iS++)):*IO::iS++)
#define putchar(x) *IO::oS++=x,IO::oS==IO::oT?flush():0
#define flush() fwrite(IO::obuf,1,IO::oS-IO::obuf,stdout),IO::oS=IO::obuf
#define puts(x) IO::Puts(x)
template<typename T>
inline void read(T&x){
for(f=1,c=getchar();c<48||c>57;c=getchar())f^=c=='-';
for(x=0;c<=57&&c>=48;c=getchar()) x=(x<<1)+(x<<3)+(c&15);
x=f?x:-x;
}
template<typename T>
inline void write(T x){
if(!x) putchar(48); if(x<0) putchar('-'),x=-x;
while(x) qu[++qr]=x%10^48,x/=10;
while(qr) putchar(qu[qr--]);
}
inline void Puts(const char*s){
for(int i=0;s[i];i++)
putchar(s[i]);
putchar('\n');
}
struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}
using IO::read;
using IO::write;
int find(int x){
if(fa[x]==x)return x;
else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
fa[find(x)]=find(y);
}
bool same(int x,int y){
return find(x)==find(y);
}
void solve(){
read(t);
for(int i=1;i<=t;i++){
query &nq=querys[i];
read(nq.i);read(nq.j);read(nq.e);
}
for(int i=1;i<=t;i++){
query &nq=querys[i];
fa[nq.i]=nq.i;
fa[nq.j]=nq.j;
}
for(int i=1;i<=t;i++){
query &nq=querys[i];
if(nq.e==1){
merge(nq.i,nq.j);
}
}
for(int i=1;i<=t;i++){
query &nq=querys[i];
if(nq.e==0){
if(same(nq.i,nq.j)){
putchar('N');putchar('O');putchar('\n');
return;
}
}
}
putchar('Y');putchar('E');putchar('S');putchar('\n');
}
int main(){
read(T);
while(T--){
solve();
}
return 0;
}
建议使用 C++14 (GCC 9) O2
。