这题?说实话,我觉得挺强的(毕竟我WA了8次,是我太cai)。
开头放题目。
首先,这是一道并查集的题目,不知道你看出来没有(反正我一开始想歪了)。
既然知道是并查集,那就是一道小破题了啊。
首先,很容易想到把所有e==1的操作放在前面,然后再进行e==0的操作。而在进行e==1的操作的时候,我们只要把它约束的两个变量放在同一个集合里面即可。在e==0,即存在一条不相等的约束条件,对于它约束的两个变量,如果在一个集合里面,那就不可能满足的啊。如不相等的约束条件都满足,那就YES。
然而并没有那么简单。不然为什么会是 省选- 呢
当我们看到数据范围->10的9次方.......(我哭了,你们呢?)
别告诉我你想开一个10的9次方的fa数组的话,MLE欢迎你。超限就凉凉啊(是我亲身经历,欢迎模仿)。
所以这时候离散化就来了啊。
离散化三部曲
- 去重。
- 排序。
- 二分。
一个unique再加lower_bound,最后再sort一下,完事。()
没学过的看这里(是我学离散化时看的博客)->https://www.cnblogs.com/cytus/p/8933597.html
又到了放代码的时候啊........
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int MA=2e5+50; int n,tot; struct ss{ int i,j,e; }ys[MA]; int a[MA],fa[MA]; bool flag; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } int cmp(ss a,ss b) { if(a.e==b.e) return a.i<b.i; return a.e>b.e; } int fi(int x) { if(fa[x]==x) return x; return fa[x]=fi(fa[x]); } void mem() { tot=0; memset(a,0,sizeof a); memset(ys,0,sizeof ys); memset(fa,0,sizeof fa); flag=0; } int main() { int t; t=read(); while(t--) { mem(); n=read(); for(register int i=1;i<=n;i++) { ys[i].i=read(); ys[i].j=read(); ys[i].e=read(); a[++tot]=ys[i].i; a[++tot]=ys[i].j; } sort(a+1,a+tot+1); int con=unique(a+1,a+tot+1)-a; for(register int i=1;i<=n;i++) { ys[i].i=lower_bound(a+1,a+con+1,ys[i].i)-a; ys[i].j=lower_bound(a+1,a+con+1,ys[i].j)-a; } for(register int i=1;i<=con;i++) fa[i]=i; sort(ys+1,ys+n+1,cmp); for(register int i=1;i<=n;i++) { int x=fi(ys[i].i); int y=fi(ys[i].j); if(ys[i].e) fa[x]=y; else if(x==y) { printf("NO "); flag=1; break; } } if(!flag) printf("YES "); } return 0; }
我的这个算法 ->2663ms.(据说超级慢,但是是正解)
然后呢这里还要介绍一下同组大佬的另一种方法(是不用离散化的........神犇方法QAQ).->300ms
https://baka.online/noi2015%E7%A8%8B%E5%BA%8F%E8%87%AA%E5%8A%A8%E5%88%86%E6%9E%90/
欢迎大家去看啊(毕竟我还是菜)。
谢谢观看。