HDU 3234 | UValive 4487 - Exclusive-OR (加权并查集)

来源:互联网 发布:白露级 程序员 编辑:程序博客网 时间:2024/05/21 11:25

Exclusive-OR

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2270    Accepted Submission(s): 634


Problem Description
You are not given n non-negative integers X0, X1, ..., Xn-1 less than 220 , but they do exist, and their values never change.

I'll gradually provide you some facts about them, and ask you some questions.

There are two kinds of facts, plus one kind of question:

 

Input
There will be at most 10 test cases. Each case begins with two integers n and Q (1 <= n <= 20,000, 2 <= Q <= 40,000). Each of the following lines contains either a fact or a question, formatted as stated above. The k parameter in the questions will be a positive integer not greater than 15, and the v parameter in the facts will be a non-negative integer less than 220. The last case is followed by n=Q=0, which should not be processed.
 

Output
For each test case, print the case number on its own line, then the answers, one on each one. If you can't deduce the answer for a particular question, from the facts I provide you before that question, print "I don't know.", without quotes. If the i-th fact (don't count questions) cannot be consistent with all the facts before that, print "The first i facts are conflicting.", then keep silence for everything after that (including facts and questions). Print a blank line after the output of each test case.
 

Sample Input
2 6I 0 1 3Q 1 0Q 2 1 0I 0 2Q 1 1Q 1 03 3I 0 1 6I 0 2 2Q 2 1 22 4I 0 1 7Q 2 0 1I 0 1 8Q 2 0 10 0
 

Sample Output
Case 1:I don't know.312Case 2:4Case 3:7The first 2 facts are conflicting.
 

Source
2009 Asia Wuhan Regional Contest Hosted by Wuhan University
 

Recommend
chenrui   |   We have carefully selected several similar problems for you:  3237 3231 3236 3232 3233 
 

Statistic | Submit | Discuss | Note



题意:

有n个小于2^20的非负整数x0, x1, x2 .. xn-1。但你并不知道他们的值,我会逐步提供一些信息,你任务是根据这些信息回答问题。

I p v 告诉你Xp = v

I p q v 告诉你 Xp ^ Xq = v

Q k q1 q2 .. qk 询问 q1 ^ q2 ^ .. qk 的值 



d[x] 表示x与父节点的异或值 : d[x] = val[x] ^ val[fa[x]]

有异或的性质可得 路径压缩的时候 d[x] = d[x] ^ d[fa[x]]

对于操作

I a v 额外建立一个节点,这里是n,val[n] 永远为0,则把a所在堆和n合并,并按照上面所说的那样维护d值

I a b  v 如果ab根节点相同,并且d[a] ^ d[b] != v 值有矛盾,返回。否则直接合并a b所在堆,并维护d值

Q k q1 q2 .. qk 求出q1 q2 ... qk 的根节点 ri r2 ... rk,然后根据根节点计算:

如果有偶数个节点,比如 q1 q3 q6 q7的根节点都是r4,那么

d[q1] ^ d[q3] ^ d[q6] ^ d[q7] = ( q1 ^ r4 ) ^ ( q3 ^ r4) ^ ( q6 ^ r4 ) ^ ( q7 ^ r4)

 = q1 ^ q3 ^ q6 ^ q7

但是如果是奇数个的情况最后会多出一个根节点,如果根节点不是n(因为val[n] = 0),则不能计算出值。





#include <cstdio>#include <iostream>#include <vector>#include <algorithm>#include <cstring>#include <string>#include <map>#include <cmath>#include <queue>#include <set>using namespace std;//#define WIN#ifdef WINtypedef __int64 LL;#define iform "%I64d"#define oform "%I64d\n"#define oform1 "%I64d"#elsetypedef long long LL;#define iform "%lld"#define oform "%lld\n"#define oform1 "%lld"#endif#define S64I(a) scanf(iform, &(a))#define P64I(a) printf(oform, (a))#define P64I1(a) printf(oform1, (a))#define REP(i, n) for(int (i)=0; (i)<n; (i)++)#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)const int INF = 0x3f3f3f3f;const double eps = 1e-9;const double PI = (4.0*atan(1.0));const int maxn = 20000 + 20;int fa[maxn], d[maxn];int n;int find(int x) {    if(fa[x] == x) return x;    int y = find(fa[x]);    d[x] = d[x] ^ d[fa[x]];    return fa[x] = y;}bool Union(int a, int b, int v) {    int pa = find(a);    int pb = find(b);    if(pa == pb) {        return (d[a] ^ d[b]) == v;    }    if(pa == n) swap(pa, pb);    fa[pa] = pb;    d[pa] = d[a] ^ d[b] ^ v;    return true;}struct Node {    int a, p;    bool operator < ( const Node & b ) const {        return p < b.p;    }} quy[30];int query(int k) {    for(int i=0; i<k; i++) {        quy[i].p = find(quy[i].a);    }    sort(quy, quy+k);    int l = 0;    int ans = 0;    while(l < k) {        int r = l;        while(r < k-1 && quy[r+1].p == quy[l].p) r++;        int num = r - l + 1;        if(quy[l].p != n && num&1) return -1;        for(int i=l; i<=r; i++) ans ^= d[quy[i].a];        l = r + 1;    }    return ans;}char str[100];int main() {    int Q;    int kase = 1;    while(scanf("%d%d", &n, &Q) != EOF && n+Q) {        for(int i=0; i<=n; i++) fa[i] = i, d[i] = 0;        printf("Case %d:\n", kase++);        int killId = -1;        int kk = 0;        while(Q--) {            scanf("%s", str);            if(str[0] == 'Q') {                int k;                scanf("%d", &k);                for(int i=0; i<k; i++) scanf("%d", &quy[i].a);                if(killId != -1) continue;                int ans = query(k);                if(ans == -1) puts("I don't know.");                else printf("%d\n", ans);            } else {                kk++;                gets(str);                if(killId != -1) continue;                int a, b, c;                int t = sscanf(str, "%d%d%d", &a, &b, &c);                int res;                if(t == 2) {                    res = Union(a, n, b);                } else {                    res = Union(a, b, c);                }                if(!res) killId = kk;            }        }        if(killId != -1) {            printf("The first %d facts are conflicting.\n", killId);        }        putchar('\n');    }    return 0;}





0 0
原创粉丝点击