hdu 3234 Exclusive-OR
2013-01-14 23:35
357 查看
Exclusive-OR
并查集的好题这里由于每次给定的是xi, xj的关系,并且可以会给定xi的值,所以我们需要3个数组来存储每个值的信息:v[i]表示i的值,p[i]表示i的父亲节点,d[i]表示v[i] ^ v[p[i]] 的值。
首先是并查集的查询操作。这里我们不仅需要压缩路径,更新x与根节点的关系,这里可以由抑或操作的传递性直接计算出来,同时如果已知x或者已知树根的值时,我们要将对应的子节点的值也求出来。这里仅仅通过抑或操作就可以直接得到节点的值或者树根的值。每当确定一个节点的数值的时候,我们便要确定该节点所在树的树根的值,这样当对节点x进行查询操作便可以直接获得x的值。这一点在合并或者赋值的时候是非常有用的
对于每个I x y c ,表示v[x]^v[y] = v, 显然如果对于已知情况,如果两个点在同一颗树上,也就是d[x] ^ d[y] == c如果成立,则满足条件,否则不满足;如果两个点不在同一个棵树上,如果根节点的值都可以得到,那么只需要d[x] ^ d[y] ^ v[p[x]] ^ v[p[y]] == c满足则不冲突,否则冲突。如果不知道其中的值,那么这个时候添加的关系肯定成立,我们只需要将两棵树合并,然后计算出树根之间的关系:d[x] ^ d[y] ^ c. 对于每个l x c, 表示v[x]
= c,这时,我们只需要将x的值求出来即可,如果x所在的树的树根有值,那么肯定可以直接计算出x(通过一次并查集的查询操作)的值,然后比较即可。
对于计算值,由于数据量比较小只有15个,暴力即可。利用抑或操作的特性,如果一个数出现偶数次,就相当于没有出现,只需要维护一个存放根以及对应该树中节点使用次数的数组。对于每个点,先进行一次查询操作,然后如果该点有值,那么将答案直接抑或这个值。否则的话,将此点放到数组中,同时更新节点出现的次数。最后对数组进行扫描,如果有一个树根节点的出现次数是奇数,说明无法确定答案,否则可以确定答案。
#include <cstdio> const int maxn = 20000+5; int p[maxn]; int v[maxn]; int d[maxn]; int count[20][2]; int cnt; void init(int n){ for(int i = 0; i < n; i ++){ p[i] = i; v[i] = -1; d[i] = 0; } } int find(int x){ if(x == p[x]) return x; int r = find(p[x]); d[x] = d[p[x]] ^ d[x]; p[x] = r; if(v[x] != -1){ v[r] = v[x] ^ d[x]; } if(v[r] != -1){ v[x] = v[r] ^ d[x]; } return r; } bool joint(int x, int y, int c){ int px = find(x); int py = find(y); if(px == py){ if((d[x] ^ d[y]) != c){ return false; } } if(v[px] != -1 && v[py] != -1){ if((v[px] ^ v[py] ^ d[x] ^ d[y] ^ c) != 0){ return false; } } else{ p[px] = py; d[px] = d[x] ^ d[y] ^ c; if(v[px] != -1){ v[py] = v[px] ^ d[px]; } else if(v[py] != -1){ v[px] = v[py] ^ d[px]; } } return true; } //如果将x的值设置为c bool set(int x, int c){ find(x); if(v[x] != -1){ if(v[x] != c) return false; } else{ v[x] = c; v[p[x]] = d[x] ^ c; } return true; } void insert(int x){ int i; for(i = 0; i < cnt; i ++){ if(count[i][0] == p[x]){ count[i][1] ++; break; } } if(i==cnt){ count[cnt][0] = p[x]; count[cnt][1] = 1; cnt ++; } } bool check(){ for(int i = 0; i < cnt; i ++){ if(count[i][1]&1){ return false; } } return true; } int main(){ int n, Q, x, y, c, ins, cas, ans; bool silence, flag; char cmd[2]; cas = 0; //freopen("data.in","r", stdin); while(scanf("%d%d", &n, &Q), n||Q){ printf("Case %d:\n", ++ cas); init(n); silence = false; flag = true; ins = 0; while(Q--){ scanf("%s", cmd); if(cmd[0]=='I'){ ins ++; scanf("%d%d", &x, &y); cmd[0] = getchar(); if(cmd[0]== ' '){ scanf("%d", &c); if(silence) continue; if(!joint(x, y, c)){ silence = true; printf("The first %d facts are conflicting.\n", ins); } } else{ if(silence) continue; if(!set(x, y)){ silence = true; printf("The first %d facts are conflicting.\n", ins); } } } else{ scanf("%d", &c); ans = 0; cnt = 0; flag = false; while(c--){ scanf("%d", &x); find(x); if(v[x] != -1){ ans = ans ^ v[x]; } else{ ans = ans ^ d[x]; insert(x); } } if(silence){ continue; } flag = check(); if(flag){ printf("%d\n", ans); } else{ printf("I don't know.\n"); } } } printf("\n"); } return 0; }
相关文章推荐
- HDU 3234 Exclusive-OR(并查集偏移向量)
- HDU 3234 | UValive 4487 - Exclusive-OR (加权并查集)
- hdu 3234 Exclusive-OR[并查集] 施工中没写完233
- [HDU 3234] Exclusive-OR
- HDU 3234 Exclusive-OR 并查集扩展
- HDU 3234 Exclusive-OR(并查集)
- HDU 3234 Exclusive-OR(加权并差集)
- HDU 3234 Exclusive-OR 扩展并查集
- HDU 3234 Exclusive-OR Regional的题就是硬啊卧槽
- hdu 3234 Exclusive-OR 有权并查集
- HDU 3234 Exclusive-OR 扩展并查集
- HDU 3234 Exclusive-OR
- HDU 3234 Exclusive-OR
- Hdu 3234 & Uva 12232 Exclusive-OR
- HDU 3234 Exclusive-OR 并查集
- HDU 3234 Exclusive-OR 并查集变形
- hdu 3234 Exclusive-OR (并查集)
- hdu 3234 Exclusive-OR
- HDU 3234 - Exclusive-OR(并查集)
- HDU 3234 Exclusive-OR 09年武汉区域赛E题