【题目】

在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设 𝑥1, 𝑥2, 𝑥3, ⋯ 代表程序中出现的变量,给定 𝑛 个形如 𝑥𝑖 = 𝑥𝑗 或 𝑥𝑖 ≠ 𝑥𝑗 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为: 𝑥1 = 𝑥2, 𝑥2 = 𝑥3, 𝑥3 = 𝑥4, 𝑥1 ≠ 𝑥4 ,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。

【题意】

输入两个建立关系的对象x,y,然后输入一个建立关系的命令。如果为1就是建立x相等y的关系,如果为0则是建立x不相等y的关系。当前建立的关系不能于之前的关系产生矛盾。如果产生矛盾则输出"NO",否则直到最后都没产生矛盾则输出"YES"。

【题解】

看完题目,可以知道也许能用并查集做,再看数据范围,可以知道不能单纯的使用并查集,还需要进行离散化。离散化的方法有两种,一种是使用单纯的数组进行离散化,还有就是使用封装好的map。前者时间复杂度相对会低一些,后者则是使用难度、代码量和出错几率会相对低一些。因为题目给的时间很宽裕,所以果断采取map来进行离散化。离散并且按命令1和命令0对x,y进行分组存储,输入数据并存储完后,先对1的命令进行并查集合并,最后则是对命令0的x,y枚举判断是否是属于同一个集合内,如果被判定为相同,则代表本来相等的对象,被再次要求不相等,这就产生了矛盾,直接输出"NO"即可,如果到最后都没有产生矛盾,则输出"YES"。

离散化:既对数字偏大,但总数偏小的数据进行重新编号存储,并应用在程序之中。

时间复杂度:并查集的操作时间复杂度是会比的速度要快,红黑树的map时间复杂度为,整体复杂度大致为

代码:

#include<iostream>
#include<cstring>
#include<sstream>
#include<string>
#include<cstdio>
#include<cctype>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<list>
#include<set>
#include<map>
#include<algorithm>
#define fi first
#define se second
#define MP make_pair
#define P pair<int,int>
#define PLL pair<ll,ll>
#define lc (p<<1)
#define rc (p<<1|1)
#define MID (tree[p].l+tree[p].r)>>1
#define Sca(x) scanf("%d",&x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)
#define Scl2(x,y) scanf("%lld%lld",&x,&y)
#define Scl3(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
#define Pri(x) printf("%d\n",x)
#define Prl(x) printf("%lld\n",x)
#define For(i,x,y) for(int i=x;i<=y;i++)
#define _For(i,x,y) for(int i=x;i>=y;i--)
#define FAST_IO std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define STOP system("pause")
#define ll long long
const int INF=0x3f3f3f3f;
const ll INFL=0x3f3f3f3f3f3f3f3f;
const double Pi = acos(-1.0);
using namespace std;
template <class T>void tomax(T&a,T b){ a=max(a,b); }  
template <class T>void tomin(T&a,T b){ a=min(a,b); }
const int N=1e6+5;
map<int,int> num;
int uck[N<<1],n,id=0,id0=0,id1=0;
struct Node{
    int x,y;
}may0[N],may1[N];
int find(int x){
    i***[x]==x) return x;
    return uck[x]=find(uck[x]);
}
inline void merge(int x,int y){
    int t1(find(x)),t2(find(y));
    if(t1!=t2) uck[t2]=t1;
}
inline void init(int n){
    For(i,1,n) uck[i]=i;
    num.clear();
}
int main(){
    int T; Sca(T);
    while(T--){
        Sca(n);
        id=0; id0=0; id1=0;
        bool flag=1;
        For(i,1,n){
            int x,y,cmd;
            Sca3(x,y,cmd);
            if(num[x]==0) num[x]=++id;
            if(num[y]==0) num[y]=++id;

            if(cmd==1) may1[++id1]=Node{num[x],num[y]};
            else may0[++id0]=Node{num[x],num[y]};
        }
        init(id);
        For(i,1,id1){
            int x=may1[i].x,y=may1[i].y;
            merge(x,y);
        }
        For(i,1,id0){
            int x=may0[i].x,y=may0[i].y;
            if(find(x)==find(y)){
                flag=0;
                break;
            }
        }
        if(flag) puts("YES");
        else puts("NO");
    }
}