题目链接:https://ac.nowcoder.com/acm/problem/17881
首先看到这道题,最简单的想法就是对于每一对相等的i,j通过并查集来建立联系,然后再去判断不相等的i,j是否有相等关系,有则不成立,没有就成立。
但是一看i和j的数据范围,头晕了。这么大的数据?????
那怎么办呢? 离散化嘛?(可是好烦啊,真的好烦啊,好复杂)
今天从毛毛雨学姐那学了一招。诈胡AC掉这道题。
对于1000000000数量级的i和j 我们将它,mod上一个较大,但是又没那么大的数。
比如mod上1e6+7 这样所有的i和j就强行缩小到我们可以接受的1e6 数量级了,再对这个范围进行并查集,应该就都没有问题了吧。
那么你该问了: 为什么可以这样做? 你这样做不对啊! 我可以举出反例!
如:
1
1 2 1
mod+1 mod+2 0
这样除余mod 以后就相当于
1
1 2 1
1 2 0
这样的输出肯定是 no
但是实际上的输出应该是yes
也就说明了这种方法是错误的
但是为什么这能称之为投机取巧的方法呢
我们来看一下他的数据量 N 是小于100000的, 那你把所有的数mod完以后 很难出现重数的情况,就算出现wa的情况,你改改这个mod,依然有大概率可以AC的。
并查集的基本操作我们就不谈了,上代码吧。
#include<iostream> #include<algorithm> #include<queue> #include<string> #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<stack> #include<set> #include<map> #define ll long long using namespace std; #define close_stdin ios::sync_with_stdio(false) const int mod = 1e6 + 7; int fa[1000007]; struct node { int x, y; }; vector<node> vec; //并查集常用操作 merge 与find int find(int x) { return(fa[x]==x?x:fa[x]=find(fa[x])); } void merge(int x, int y) { fa[find(x)] = find(y); } void solve() { for (int i = 1;i <= mod;i++) { fa[i] = i; } int n; vector<node>vec; cin >> n; while (n--) { int i, j, e; cin >> i >> j >> e; i %= mod;j %= mod; if(!e){ node temp; temp.x = i;temp.y = j; vec.push_back(temp); } else { merge(i, j); } } for (auto w : vec) { if (find(w.x) == find(w.y)) { cout << "NO\n";return; } } cout << "YES\n"; } int main() { close_stdin;//只是为了让cin和printf一样快 int T; cin >> T; while (T--) { solve(); } }