题目链接

https://ac.nowcoder.com/acm/problem/204870

题目大意

t组数据输入,n个关系,每个关系包括三个数a,b两个人,c=1表示二者互为好朋友,c=0表示二者互为敌人,遵循朋友的朋友就是朋友的原则,问这组数据是否自相矛盾,(如果两个人既是友好的又是不友好的则视为相互矛盾的),不矛盾输出YES,矛盾输出NO。

题目分析

一打眼过去,并查集吧。因为有“朋友的朋友就是朋友”,显然是连通区域。
(不会并查集的可以看一下 并查集例题及讲解链接
并查集有了,但是发现总人数是1e9个人,实际给出的关系只有1e6个,这就说明…………要离散化!
如何离散化呢?
对我这种小白来说感觉好巧妙,但是大佬的题解都是一笔带过。

//离散化核心代码
//-----------------------------------------
for(int i=1;i<=n;i++){
    cin>>a[i]>>b[i]>>c[i];
}
for(int i=1;i<=n;i++){
    d[++cnt]=a[i];
    d[++cnt]=b[i];
}
sort(d+1,d+1+cnt);
cnt=unique(d+1,d+1+cnt)-d;
for(int i=1;i<=n;i++){
    a[i]=lower_bound(d+1,d+cnt+1,a[i])-d;
    b[i]=lower_bound(d+1,d+cnt+1,b[i])-d;
}
//-----------------------------------------

离散化过程讲解:
S1:先把a,b,c存储在数组里;
S2:(重新回忆一下a,b分别代表什么?两个人的序号吧)因为a,b所涉及到的人才是我们应该去关心的,而剩下的人(最少剩下1e9-2*1e6人)是我们不关心的,因此离散化是显而易见的,我们就把a,b涉及到的人都存储到一个d数组中;
S3:将d数组从小到大排序,利用unique函数除重,算出涉及到的总人数;
S4:最后通过lower_bound函数为每个人重新分配序号,(按照每个人原序号的相对大小关系排序,原序号所对应位置的索引就是新序号)从而实现了离散化。
ps: unique函数基础讲解

离散化完成之后,进行fa数组的初始化,开始构建连通区域。
遍历所有的c,若c=1,那么构建连通区域;
再遍历所有的c,若c!=1,那么判断一下,若此时对应的a和b对应的连通区域相同,wrong标志置一,表示矛盾了;反之wrong表示不变为0,表示不矛盾。

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
const int M=2*N;
int fa[M], d[M];
int a[N], b[N], c[N];
int find(int x){//太简洁了,实现了find操作,而且还进行了路径压缩
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main(){
    int t,n,cnt;
    cin>>t;
    while(t--){
        cnt=0;
        cin>>n;
//-------------------------离散化----------------------------------
        for(int i=1;i<=n;i++){
            cin>>a[i]>>b[i]>>c[i];
        }
        for(int i=1;i<=n;i++){
            d[++cnt]=a[i];
            d[++cnt]=b[i];
        }
        sort(d+1,d+1+cnt);
        cnt=unique(d+1,d+1+cnt)-d;
        for(int i=1;i<=n;i++){
            a[i]=lower_bound(d+1,d+cnt+1,a[i])-d;
            b[i]=lower_bound(d+1,d+cnt+1,b[i])-d;
        }
//-----------------------------------------------------------------

//-------------------------初始化----------------------------------
        for(int i=1;i<=cnt;i++){
            fa[i]=i;
        }
//-----------------------------------------------------------------

//-------------------------判断-------------------------------------
        for(int i=1;i<=n;i++){
            if(c[i]==1){
                int rx=find(a[i]),ry=find(b[i]);
                if(rx!=ry)
                    fa[rx]=ry;
            }
        }
        int w=0;
        for(int i=1;i<=n;i++){
            if(c[i]!=1){
                if(find(a[i])==find(b[i])) w=1;
            }
        }
//----------------------------------------------------------------

//-------------------------输出------------------------------------
        cout<<(w==1?"NO":"YES")<<endl;
    }
} 

总结

挺难的,离散化不会,并查集用的也不熟。最后c的判断也挺巧妙。
过一阵写一下离散化,出份题解。
最后的最后我还想再问一句:我什么时候才能成为大佬啊啊啊!!!