UVALive 4487 - Exclusive-OR (加权并查集+异或运算的性质)

题目链接 https://cn.vjudge.net/problem/UVALive-4487

【题意】
已知有 x[0-(n-1)],但是不知道具体的值,题目给定的信息 只有 I P V,说明 Xp=V,或者 I P Q V,说明 Xp ^ Xq=v,然后要求回答每个询问,询问的是 某任意的序列值 Xp1^Xp2,,,,X^pk

【思路】
一道很难想的并查集的题目,看了大神的博客才弄懂,这里不啰嗦了,最后一定要注意由于异或运算优先级低,一定要加括号. 还是太菜了,代码也是照着人家的写.
UVALive 4487 Exclusive-OR 加权并查集神题 - KRisen - 博客园

#include<bits/stdc++.h>
using namespace std;

const int maxn=20050;
const int rt=maxn-5;

int n,Q;
int par[maxn];
int v[maxn],cnt[maxn];

void init(){
    memset(v,0,sizeof(v));
    memset(cnt,0,sizeof(cnt));
    for(int i=0;i<maxn;++i) par[i]=i;
}

int find(int x){
    if(x!=par[x]){
        int tmp=par[x];
        par[x]=find(par[x]);
        v[x]^=v[tmp];
    }
    return par[x];
}

bool merge(int p,int q,int val){
    int r1=find(p);
    int r2=find(q);
    if(r1==r2){
        return (v[p]^v[q])==val;
    }
    if(r1==rt) swap(r1,r2);
    par[r1]=r2;
    v[r1]=v[p]^v[q]^val;
    return true;
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int kase=0;
    while(scanf("%d%d",&n,&Q)==2){
        if(0==n && 0==Q) break;
        init();
        bool ok=true;
        int fac=0;
        printf("Case %d:\n",++kase);
        while(Q--){
            char op[50];
            scanf("%s",op);
            if(op[0]=='I'){
                ++fac;
                gets(op);
                if(!ok) continue;
                int p,q,val;
                if(sscanf(op,"%d%d%d",&p,&q,&val)==2){
                    val=q;
                    q=rt;
                }
                if(!merge(p,q,val)){
                    ok=false;
                    printf("The first %d facts are conflicting.\n",fac);
                }
            }
            else{
                int k,a[20],ans=0;
                scanf("%d",&k);
                for(int i=0;i<k;++i){
                    scanf("%d",&a[i]);
                    if(!ok) continue;           
                    int r=find(a[i]);
                    ans^=v[a[i]];
                    a[i]=r;
                    cnt[r]^=1;
                }
                if(!ok) continue;
                bool flag=true;
                for(int i=0;i<k;++i){
                    if(cnt[a[i]] && a[i]!=rt) { flag=false; }
                    cnt[a[i]]=0;
                }
                if(flag) printf("%d\n",ans);
                else puts("I don't know.");
            }
        }
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值