HDU 3234 Exclusive-OR(加權並差集)

Exclusive-OR

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


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

題意:
對於n個數a[0]~a[n-1],但你不知道它們的值,通過逐步提供給你的信息,你的任務是根據這些信息回答問題

I P V :告訴你a[P] = V
I P Q V:告訴你a[P] XOR a[Q] = V
Q K P1..PK:詢問a[P1]^a[P2]^...a[PK]的值

思路:
很經典的並查集題目
r[a]記錄的是a與其父親節點的異或值
通過並查集合並的過程同時更新路徑上的r值
令fa,fb分別是a,b,的父親節點
我們知道r[a] = a^fa,r[b]=b^fa,a^b=c
那麼在合併fa,fb的時候,令fb爲fa的父節點
那麼就有r[fa]=fa^fb
而r[a]=a^fa,所以fa=a^r[a]
同理fb=b^r[b]
所以r[fa] = r[a]^r[b]^a^b = r[a]^r[b]^c
當然對於一個節點合併問題不好解決,此時可以添加一一個新節點n作爲根節點,使得n的值爲0,那麼任何值與0的異或都是本身
這樣一來合併問題就解決了

然後對於查詢而言,對於n是根節點的我們不需要考慮,但是對於不是以n爲跟節點的,根節點的值被重複計算了,這個時候我們要統計根節點被統計的次數,如果是奇數次,那麼必然是無法確定的了

<span style="font-size:18px;"> #include<iostream>
 #include<cstdio>
 #include<algorithm>
 #include<cmath>
 #include<cstring>
 using namespace std;
 const int maxn=20005;
 int fa[maxn],d[maxn];
 int n;
 struct node
 {
     int a,p;
     bool operator<(const node& b)const{
        return p<b.p;
     }
 }quy[30];
 int find(int x){
    if(x==fa[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;
 }
 int query(int k)
 {
     for(int i=0;i<k;i++)
        quy[i].p=find(quy[i].a); //cout << quy[i].p << endl;
     int l=0;
     int ans=0;
     sort(quy,quy+k);
     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;
        //cout << -1 << endl;
     }
     return ans;
 }
 int main()
 {
     char str[100];
     int Q,cas=0;
     while(~scanf("%d%d",&n,&Q) && n+Q)
     {
         for(int i=0; i<=n;i++) fa[i]=i,d[i]=0;
         printf("Case %d:\n",++cas);
         int killid=-1,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;
                //cout << t  << endl;
                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",kk);
         }
         printf("\n");
     }
     return 0;
 }
</span>


發佈了106 篇原創文章 · 獲贊 5 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章