zoukankan      html  css  js  c++  java
  • hdu 3234 Exclusive-OR

    Exclusive-OR

    题意:输入n个点和Q次操作(1 <= n <= 20,000, 2 <= Q <= 40,000).操作和叙述的点标号k(0 < k < n)

    操作分为I & Q两种,I又分为 I a v表示val[a] = v和 I a b v 即val[a] ^ val[b] = v; Q k X0,X1...Xk-1表示求出X0^X1^...^Xk-1 = ?

    对于每个Q操作,结果分为 I don't know.即不能求解或输出确定值,对于每组叙述操作,若叙述与之前的矛盾则输出改标号:The first 2 facts are conflicting.且该组后面的操作直接忽略;

    Sample Input (只是一组)
    2 6
    I 0 1 3
    Q 1 0
    Q 2 1 0
    I 0 2
    Q 1 1
    Q 1 0
    0 0
    Sample Output
    Case 1:
    I don't know.
    3
    1
    2
     
    思路:根据压缩路径的同时可以得到每个子节点到根节点的XOR的相对值;即XOR[i] = XOR[i] ^ XOR[root];将该异或结果存储在子节点中。当根节点未知时,不能确定子节点的值;但是根据XOR的特性可知,当子节点的个数为偶数时,就可以将根节点消去,这就是在求解Q 操作时,对于每个id[]都是分集合(同根节点)求解的。此题有一个区别就是可以根据I操作知道若干个节点的值,并且可以根据XOR的关系推出其他节点的值。这个特性甚是无语啊。。(难点)那么是否就需要另外存储每一个节点的值?这么想会发现很复杂,因为这脱离了并查集;每次需要判断是否是确定值,并且之间的推断感觉不好编码,这是需要转化为并查集;
     
    构造:构造出一个节点n,表示所有已知值的根节点;这时可以将已知节点的值直接看成是该节点与根节点n的XOR值,和未知值节点的共性;
    细节:对于在_union()中,判断fa是否为n,这一点是为了维护n一定是已知值节点的根节点;不能认为a反正不会是n,而去除;
     
    code是参考了ACM_cxlove (是我网上看到除了notonlySuccess的线段树之外,写得最好的code,顶一个,风格和我差不多。。)后自己写的;痕迹明显。。
     
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    const int MAXN = 20020;
    int n,f[MAXN];
    int XOR[MAXN],id[MAXN<<1];//每个点到根节点(压缩之后)的XOR,以及Q查询的id;
    int Find(int a)//**
    {
        if(a == f[a]) return a;
        int fa = Find(f[a]);
        XOR[a] ^= XOR[f[a]];
        return f[a] = fa;
    }
    bool _union(int a,int b,int v)
    {
        int fa = Find(a),fb = Find(b);
        if(fa == fb){//同一个集合就可以计算出两个点之间的异或值;和下面的偶数一致
            if((XOR[a] ^ XOR[b]) != v) return false;
            return true;
        }
        if(fa == n) swap(fa,fb);//是对于输入了a,b,v来看的,并不是对a v,b = n来设置的
        f[fa] = fb;
        XOR[fa] = XOR[b]^v^XOR[a];
        return true;
    }
    char op[1000];
    int vis[20];
    int Query(int k)
    {
        MS0(vis);
        int ans = 0;
        rep0(i,0,k){
            int cnt = 0;
            int root = Find(id[i]);
            rep0(j,i,k){
                if(!vis[j] && Find(id[j]) == root){//同属一个集合;
                    cnt++;
                    vis[j] = true;
                    ans ^= XOR[id[j]];
                }
            }
            if(root != n && (cnt & 1)) return -1;
        }
        return ans;
    }
    int main()
    {
        int Q,kase = 1;
        while(scanf("%d%d",&n,&Q) == 2 && n + Q){
            rep1(i,0,n) f[i] = i,XOR[i] = 0;
            printf("Case %d:
    ",kase++);
            int cnt_i = 0,flag = 0;
            while(Q--){
                scanf("%s",op);
                if(op[0] == 'I'){
                    int space = 0,a,b,v;
                    cnt_i++;
                    getchar();gets(op);
                    rep0(i,0,strlen(op))if(op[i] == ' ') space++;
                    if(space & 1){
                        sscanf(op,"%d%d",&a,&v);
                        b = n;
                    }else{
                        sscanf(op,"%d%d%d",&a,&b,&v);
                    }
                    //printf(" %d %d %d
    ",a,b,v);
                    if(!flag && !_union(a,b,v)){
                        printf("The first %d facts are conflicting.
    ",cnt_i);
                        flag = 1;
                    }
                }else{
                    int k;
                    scanf("%d",&k);
                    rep0(i,0,k){
                        scanf("%d",id+i);
                    }
                    if(flag)continue;
                    int ret = Query(k);
                    if(ret == -1) puts("I don't know.");
                    else printf("%d
    ",ret);
                }
            }
            puts("");
        }
        return 0;
    }
    View Code
     
     
     
  • 相关阅读:
    Python之遍历所有行
    Python之找到所有空值所在行
    Python之根据条件筛选特定行
    Python之ArcGIS的字段计算器的运用
    Python之时间格式的快速处理
    Python之多列数据(元组)同时写入DataFrame不同列
    Python之对DataFrame的多列数据运用apply函数操作
    ubuntu12 配置samba服务 实现文件共享 分类: ubuntu 测试 虚拟机 2015-04-25 20:35 38人阅读 评论(0) 收藏
    判断一个对象是否可迭代 的方法 分类: python 2015-03-27 12:20 82人阅读 评论(0) 收藏
    ubuntu中设置tomcat自启动 分类: ubuntu 测试 2015-02-28 17:15 66人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/hxer/p/5185823.html
Copyright © 2011-2022 走看看