LA4487 Exclusive-OR (加权并查集)
来源:互联网 发布:知乎禁止转载怎么复制 编辑:程序博客网 时间:2024/06/06 07:34
题意: 有N个数X[0] ~ X[N], 事先并不知道他们的值,有三种操作(^为异或):
I P V :告诉你X[P] = V
I P Q V:告诉你X[P] ^ X[Q] = V
Q K P1..PK:询问X[P1]^X[P2]^...X[PK]的值
如果信息矛盾 或者 不能知道查询的结果输出一些提示信息。
思路:对于第一种操作, X[P] = V 可以看做第二种操作的 X[P] ^ 0 = V, 新增一个节点n, 他的值为0。
对于查询, 我们知道, 如果有a ^ b = x1, b ^ c = x2, 可以得出 a ^ c = x1 ^ x2, 那么如果Xa ^ Xb = v为a, b连接一条边,权值为v,则a^b能求出结果的条件是a, b有相同的根节点,这里可以使用并查集, 注意在合并的时候需要进行路径压缩, 即每一节点有一个与根节点异或的值。那么在查询的时候, 先把不同集合里面的节点分开, 相同集合里面的节点放一起, 在同一个集合里面, 如果根节点是n, 那么一定可以得出所有节点的异或值, 如果不为n, 那么只要出现节点个数为奇数的集合就不能得出结果, 否则将每个节点的值异或起来即可。
#include<cstdio>#include<cstring>#include<cmath>#include<vector>#include<iostream>#include<algorithm>const int maxn = 2e4 + 10;using namespace std;int n, Q;char cmd[maxn];int pa[maxn], dis[maxn];int num, r[50], fac;int read() { int len = strlen(cmd); num = 0; for(int i = 0; i < len; i++) { if(cmd[i] < '0' || cmd[i] > '9') continue; int j = i, sum = 0; while(j < len && cmd[j] >= '0' && cmd[j] <= '9') { sum = sum * 10 + cmd[j] - '0'; j++; } r[num++] = sum; i = j; } char ch = cmd[0]; if(ch == 'Q') return 3; fac++; if(num == 2) return 1; return 2;}int findset(int x) { if(x == pa[x]) return x; int px = findset(pa[x]); dis[x] ^= dis[pa[x]]; return pa[x] = px;}bool can_unit(int x, int y, int val) { int nx = findset(x), ny = findset(y); if(nx == ny && (dis[x] ^ dis[y]) != val) return false; if(nx == ny) return true; if(nx == n + 1) { pa[ny] = nx; dis[ny] = dis[x] ^ dis[y] ^ val; } else { pa[nx] = ny; dis[nx] = dis[x] ^ dis[y] ^ val; } return true;}vector<int> G[50];int fa[50];int main() { int kase = 1; while(scanf("%d %d", &n, &Q) && n) { fac = 0; for(int i = 0; i <= n + 2; i++) { pa[i] = i; dis[i] = 0; } gets(cmd); bool ans = true; printf("Case %d:\n", kase++); while(Q--) { gets(cmd); if(!ans) continue; int op = read(); if(op == 1) { int p = r[0], v = r[1]; if(!can_unit(p, n + 1, v)) { ans = false; printf("The first %d facts are conflicting.\n", fac); } } else if(op == 2) { int p = r[0], q = r[1], v = r[2]; if(!can_unit(p, q, v)) { ans = false; printf("The first %d facts are conflicting.\n", fac); } } else { int x = 0; for(int i = 0; i < 20; i++) G[i].clear(); for(int i = 1; i < num; i++) { int id = r[i], nx = findset(id); bool have = false; for(int j = 0; j < x; j++) { if(fa[j] != nx) continue; have = true; G[j].push_back(id); break; } if(have) continue; G[x].push_back(id); fa[x] = nx; x++; } bool solve = true; int res = 0; for(int i = 0; i < x; i++) { if(fa[i] != n + 1 && G[i].size() % 2 == 1) { solve = false; break; } for(int j = 0; j < G[i].size(); j++) { int k = G[i][j]; res ^= dis[k]; } } if(!solve) printf("I don't know.\n"); else printf("%d\n", res); } } printf("\n"); } return 0;}
阅读全文
0 0
- 正则表达式之完全体验
- 为什么要用markdown写作
- Mac电脑截图快捷键
- 移动端适配
- Mtalab 运行问题:java.lang.OutOfMemoryError:Java heap space
- LA4487 Exclusive-OR (加权并查集)
- 安装composer
- 计算机网络:TCP套接字通信
- hdu 4366
- FastDFS实战(五)- Spring Boot集成FastDFS
- MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)的理解
- 方法和函数的区别
- 正则表达式之问号
- 各大公司Java后端开发面试题总结