WuHan 2009 / UVa 12232 / HDU 3234 Exclusive-OR (异或的性质&加权并查集&合并时保持根结点不变)

来源:互联网 发布:ipad 知乎 编辑:程序博客网 时间:2024/06/05 08:03

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=3384

http://acm.hdu.edu.cn/showproblem.php?pid=3234


1. 对于第一种命令I p v,我们可以虚拟出一个点Xn = 0,那么p^Xn = v,故第一和第二种命令我们可以统一成p^q = v的模式。

2. 对于第三种命令,记val[i] = Xi^Xfa[i],那么Xp1^Xp2^...^Xpk = (val[Xp1]^...^val[Xpk]) ^ (Xfa[Xp1]^...^Xfa[Xpk])

val[Xp1]^...^val[Xpk]易求,对于Xfa[Xp1]^...^Xfa[Xpk],由于a^c^b^c = a^b,可先判断Xfa[Xpi]出现的次数的奇偶性,偶数不用管,奇数看Xfa[Xpi]是否为Xn,若不是则在Xp1^Xp2^...^Xpk中必有未知信息,若是则异或Xfa[Xpi]即可。


完整代码:

/*0.102s*/#include<bits/stdc++.h>using namespace std;const int mx = 20005;int val[mx], fa[mx], n;char str[100];int find(int x){if (~fa[x]){int tmp = fa[x];fa[x] = find(fa[x]);val[x] ^= val[tmp]; ///pushdownreturn fa[x];}return x;}bool merge(int x, int y, int v){int fx = find(x), fy = find(y);if (fx == fy) return (val[x] ^ val[y]) == v;if (fx == n) swap(fx , fy); ///技巧:始终使得Xn(虚拟的点)为根结点fa[fx] = fy, val[fx] = val[x] ^ v ^ val[y];return true;}int main(){//freopen("in.txt", "r", stdin);int m, p, q, v, k, x, ans, cas = 0, facts;bool isError;map<int, int> mp;map<int, int>::iterator iter;while (scanf("%d%d", &n, &m), n){getchar();printf("Case %d:\n" , ++cas);memset(val, 0, sizeof(val));memset(fa, -1, sizeof(fa));facts = 0;isError = false;while (m--){if (getchar() == 'I'){gets(str);++facts;if (isError) continue;if (sscanf(str, "%d%d%d", &p, &q, &v) == 2) v = q, q = n; ///换成根结点if (!merge(p, q, v)){isError = true;printf("The first %d facts are conflicting.\n" , facts++);}}else{scanf("%d", &k);ans = 0;mp.clear();while (k--){scanf("%d", &x);if (isError) continue;find(x); ///更新一下值再计算ans ^= val[x];++mp[find(x)];}getchar();if (isError) continue;for (iter = mp.begin(); iter != mp.end(); ++iter){if (iter->second & 1){if (iter->first != n) break; ///存在未知信息else ans ^= val[iter->first];}}if (iter == mp.end()) printf("%d\n" , ans);else puts("I don't know.");}}putchar(10);}return 0;}

0 0
原创粉丝点击