Exclusive-OR(带权并查集)

Exclusive-OR

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 152 Accepted Submission(s): 55
 
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 6
I 0 1 3
Q 1 0
Q 2 1 0
I 0 2
Q 1 1
Q 1 0
3 3
I 0 1 6
I 0 2 2
Q 2 1 2
2 4
I 0 1 7
Q 2 0 1
I 0 1 8
Q 2 0 1
0 0
 
Sample Output
Case 1:
I don't know.
3
1
2
Case 2:
4
Case 3:
7
The first 2 facts are conflicting.
 
 
Source
2009 Asia Wuhan Regional Contest Hosted by Wuhan University
 
Recommend
chenrui
 
/*
题意:有n个数,但是n个数还没确定,有两种操作:
    I:p v告诉你Xp的值。
    I:p q v告诉你Xp^Xq=v。
    Q:k p1 p2...pk 询问 Xp1^Xp2...^Xpk=?
    如果I操作有矛盾请指出。

初步思路:带权并查集。r[i]数组表示i与根节点的异或值,查询的时候,r[a]^r[b]实际上就是a^b的值,因为,父节点的已经
    已经异或掉了,很显然如果是奇数个肯定是求不出来的
*/
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
char op[100];
int num[20005];//存放各种数据
int father[20005];//存储i的父节点
int r[20005];//存放i与父节点的异或
int vis[20005];//记录访问过的点
int ca=1;
int u,v,c;
char str[100];
int times=0;//用来记录I操作进行了几次
int findx(int x){
    if(x!=father[x])
    {
        int fx = father[x];
        father[x] = findx(father[x]);
        r[x]^=r[fx];
    }
    return father[x];
}
bool Union(int x,int y,int z){
    int fx=findx(x);
    int fy=findx(y);
    if(fx==fy){
        if((r[x]^r[y])!=z)
            return false;
        return true;
    }
    if(fx==n) swap(fx,fy);
    father[fx]=fy;
    r[fx] = r[x]^r[y]^z;
    return true;
}
int query(){
    memset(vis,0,sizeof vis);
    int ans=0;
    for(int i=0;i<k;i++){
        if(vis[i]) continue;
        int cnt=0;
        int root=findx(num[i]);
        for(int j=i;j<k;j++) {
            if(!vis[j] && root == findx(num[j])){
                vis[j] = 1;
                cnt++;
                ans^=r[num[j]];
            }
        }
        if(root!=n&&(cnt&1)){
            return -1;
        }
    }
    return ans;
    
}
void init(){
    memset(r,0,sizeof r);
    for(int i=0;i<=n;i++){
        father[i]=i;
    }
    times=0;
}
int main(){
    // freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){
        init();
        printf("Case %d:
",ca++);
        bool flag=false;//表示命令的正确性
        for(int i=0;i<m;i++){
            scanf("%s",op);
            // cout<<op<<" ";
            getchar();
            if(op[0]=='I'){
                times++;
                gets(str);
                // cout<<str<<endl;
                if(flag) continue;
                int cur=0;
                for(int i=0;str[i];i++){
                    if(str[i]==' ') cur++;
                }
                if(cur==1){//u c
                    sscanf(str,"%d%d",&u,&c);
                    v=n;
                    // cout<<u<<" "<<c<<endl;
                }else{//u v c
                    sscanf(str,"%d%d%d",&u,&v,&c);
                    // cout<<u<<" "<<v<<" "<<c<<endl;
                }
                if(!Union(u,v,c))
                {
                    printf("The first %d facts are conflicting.
",times);
                    flag = true;
                }
            }else{
                scanf("%d",&k);
                // cout<<k<<" ";
                for(int i=0;i<k;i++){
                    scanf("%d",&num[i]);
                    // cout<<num[i]<<" ";
                }
                // cout<<endl;
                if(flag) continue;
                int ans = query();
                if(ans == -1)
                    printf("I don't know.
");
                else
                    printf("%d
",ans);
            }
        }
        // for(int i=0;i<n;i++){
                // cout<<father[i]<<" ";
            // }
            // cout<<endl;
        printf("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wuwangchuxin0924/p/6430656.html