
本文共 5294 字,大约阅读时间需要 17 分钟。
题目描述
给 n n n 组操作,每组操作形式为 x y p x\ y\ p x y p。
当 p p p 为 1 1 1 时,如果第 x x x 个变量和第 y y y 个变量可以相等,则输出YES,并限制他们相等;否则输出 NO,并忽略此次操作。
当 p p p 为 0 0 0 时,如果第 x x x 个变量和第 y y y 个变量可以不相等,则输出 YES,并限制他们不相等;否则输出 NO,并忽略此次操作。
输入格式
第一行为一个正整数 n n n。 接下来 n n n 行每行三个整数: x x x, y y y, p p p。
输出格式
对于 n n n 行操作,分别输出 n n n 行 YES 或者 NO。
样例
输入
31 2 11 3 12 3 0
样例输出
YESYESNO
数据范围与提示
1 ≤ n ≤ 1 0 5 1\leq n \leq 10^5 1≤n≤105, 1 ≤ x , y ≤ 1 0 8 1\leq x,y\leq10^8 1≤x,y≤108, p = 1 p=1 p=1 或 0 0 0。
分析
显然,这是一道并查集的题。因为 1 ≤ x , y ≤ 1 0 8 1\leq x,y\leq10^8 1≤x,y≤108,所以这道题需要离散化。
考虑 p = 1 p=1 p=1 的情况,显然把这两个集合合并就行了。
难点在 p = 0 p=0 p=0的情况,因为 x ≠ y x\neq y x=y, y ≠ z y \neq z y=z并不能推出 x = z x=z x=z,所以这个地方没有传递性。那怎么办呢?你可以用 v i s [ i ] [ j ] vis[i][j] vis[i][j]表示 i i i和 j j j不相等(只是数组不能开题目规定的这么大),还可以用 s e t set set,将与 i i i不相等的点都装进 s e t [ i ] set[i] set[i]中(为什么不用 v e c t o r vector vector呢?因为 s e t set set可以自动去重)。然而我们要考虑传递:
1.数组法(比较好写)。
当 p = 0 p=0 p=0,易知
vis[i][j] = 1;//i != j vis[j][i] = 1;//同上
当 p = 1 p=1 p=1,易知
for(int k = 1; k <= num; k ++) { vis[i][k] |= vis[j][k];//若j != k则i != k vis[k][i] |= vis[k][j];//同上 vis[j][k] = vis[i][k];//因为i = j,所以若i != k则j != k vis[k][j] = vis[k][i];//同上}
2. s e t set set
当 p = 0 p=0 p=0
s[i].insert(j); //插入s[j].insert(i); //同上
当 p = 1 p=1 p=1
if(rank[i] < rank[j]) { fa[i] = j; for(set <int>::iterator it = s[i].begin(); it != s[i].end(); it ++) { s[j].insert(*it);//因为i = j,所以若(*it) != i,则(*it) != j } for(set <int>::iterator it = s[j].begin(); it != s[j].end(); it ++) { s[*it].insert(j);//若(*it) != j,则将j加入到set[(*it)]中 }}else { fa[j] = i; if(rank[i] == rank[j]) rank[i] ++; for(set <int>::iterator it = s[j].begin(); it != s[j].end(); it ++) { s[i].insert(*it);//因为i = j,所以若(*it) != j,则(*it) != i } for(set <int>::iterator it = s[i].begin(); it != s[i].end(); it ++) { s[*it].insert(i);//若(*it) != i,则将i加入到set[(*it)]中 }}
这里我用了启发式合并,因为 i = j i=j i=j,对于任意的 k k k,如果 i ! = k i\ !=k i !=k(即 k k k 在 s e t [ i ] set[i] set[i] 中),则 j ! = k j!=k j!=k(即 k k k 在 s e t [ j ] set[j] set[j] 中)。同理, i i i 和 j j j 都在 s e t [ k ] set[k] set[k] 中。
代码
法一
#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <climits>using namespace std;const int MAXN = 2 * 1e5 + 5;int n, fa[MAXN], rank[MAXN], lsh[MAXN], X[MAXN], Y[MAXN], Z[MAXN], cnt, num;bool vis[25000][25000];void Make_Set(int x) { for(int i = 1; i <= x; i ++) { //初始化 fa[i] = i; rank[i] = 1; } return;}int Find_Set(int x) { //找父亲(路径压缩) if(x != fa[x]) { return fa[x] = Find_Set(fa[x]); } return fa[x];}bool Union_Set(int x, int y, int z) { //合并 int i = Find_Set(x), j = Find_Set(y); if(z == 1) { if(i == j) return 1; if(vis[i][j]) return 0; if(rank[i] < rank[j]) fa[i] = j; else { fa[j] = i; if(rank[i] == rank[j]) rank[i] ++; } for(int k = 1; k <= num; k ++) { vis[i][k] |= vis[j][k]; vis[k][i] |= vis[k][j]; vis[j][k] = vis[i][k]; vis[k][j] = vis[k][i]; } } else { if(i == j) return 0; vis[i][j] = 1; vis[j][i] = 1; } return 1;}int main() { int x, y; scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("%d%d%d", &X[i], &Y[i], &Z[i]); lsh[++ cnt] = X[i]; lsh[++ cnt] = Y[i]; } sort(lsh + 1, lsh + 1 + cnt);//离散化 num = unique(lsh + 1, lsh + 1 + cnt) - lsh - 1; Make_Set(num); for(int i = 1; i <= n; i ++) { x = lower_bound(lsh + 1, lsh + 1 + num, X[i]) - lsh; y = lower_bound(lsh + 1, lsh + 1 + num, Y[i]) - lsh; if(Union_Set(x, y, Z[i])) printf("YES\n"); else { printf("NO\n"); } } return 0;}
法二
#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <climits>#include <vector>#include <set>using namespace std;const int MAXN = 2 * 1e5 + 5;int n, fa[MAXN], rank[MAXN], lsh[MAXN], X[MAXN], Y[MAXN], Z[MAXN], cnt, num;set <int> s[MAXN];void Make_Set(int x) { //初始化 for(int i = 1; i <= x; i ++) { fa[i] = i; rank[i] = 1; } return;}int Find_Set(int x) { //找父亲(路径压缩) if(x != fa[x]) { return fa[x] = Find_Set(fa[x]); } return fa[x];}bool Union_Set(int x, int y, int z) { //合并 int i = Find_Set(x), j = Find_Set(y); if(z == 1) { if(i == j) return 1; set <int>::iterator it = s[i].find(j); set <int>::iterator it1 = s[j].find(i); if(it != s[i].end() || it1 != s[j].end()) return 0; if(rank[i] < rank[j]) { fa[i] = j; for(set <int>::iterator it = s[i].begin(); it != s[i].end(); it ++) { s[j].insert(*it); } for(set <int>::iterator it = s[j].begin(); it != s[j].end(); it ++) { s[*it].insert(j); } } else { fa[j] = i; if(rank[i] == rank[j]) rank[i] ++; for(set <int>::iterator it = s[j].begin(); it != s[j].end(); it ++) { s[i].insert(*it); } for(set <int>::iterator it = s[i].begin(); it != s[i].end(); it ++) { s[*it].insert(i); } } } else { if(i == j) return 0; s[i].insert(j); s[j].insert(i); } return 1;}int main() { int x, y; scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("%d%d%d", &X[i], &Y[i], &Z[i]); lsh[++ cnt] = X[i]; lsh[++ cnt] = Y[i]; } sort(lsh + 1, lsh + 1 + cnt);//离散化 num = unique(lsh + 1, lsh + 1 + cnt) - lsh - 1; Make_Set(num); for(int i = 1; i <= n; i ++) { x = lower_bound(lsh + 1, lsh + 1 + num, X[i]) - lsh; y = lower_bound(lsh + 1, lsh + 1 + num, Y[i]) - lsh; if(Union_Set(x, y, Z[i])) printf("YES\n"); else { printf("NO\n"); } } return 0;}
发表评论
最新留言
关于作者
