HDU3234&&UVA12232&&LA4487:Exclusive-OR(经典带权并查集)

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为跟节点的,根节点的值被重复计算了,这个时候我们要统计根节点被统计的次数,如果是奇数次,那么必然是无法确定的了

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <list>
#include <algorithm>
#include <climits>
using namespace std;

#define lson 2*i
#define rson 2*i+1
#define LS l,mid,lson
#define RS mid+1,r,rson
#define UP(i,x,y) for(i=x;i<=y;i++)
#define DOWN(i,x,y) for(i=x;i>=y;i--)
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define LL long long
#define N 20005
#define INF 0x3f3f3f3f
#define EXP 1e-8
#define lowbit(x) (x&-x)
const int mod = 1e9+7;

int n,m,tot;
int father[N],r[N],num[N],u,v,w,vis[N];
char str[100];

int find(int x)
{
    if(x!=father[x])
    {
        int fx = father[x];
        father[x] = find(father[x]);
        r[x]^=r[fx];
    }
    return father[x];
}

bool Union(int a,int b,int c)
{
    int fa = find(a),fb=find(b);
    if(fa==fb)
    {
        if((r[a]^r[b])!=c) return false;
        return true;
    }
    if(fa==n) swap(fa,fb);
    father[fa] = fb;
    r[fa] = r[a]^r[b]^c;
    return true;
}

int query()
{
    int i,j,cnt,ans = 0;
    MEM(vis,0);
    for(i = 0; i<tot; i++)
    {
        if(vis[i]) continue;
        cnt = 0;
        int root = find(num[i]);
        for(j = i; j<tot; j++)
        {
            if(!vis[j] && root == find(num[j]))
            {
                vis[j] = 1;
                cnt++;
                ans^=r[num[j]];
            }
        }
        if(root!=n&&(cnt&1))
        {
            return -1;
        }
    }
    return ans;
}

int main()
{
    int i,j,k,cas = 1;
    while(~scanf("%d%d",&n,&m),n+m)
    {
        printf("Case %d:\n",cas++);
        for(i = 0; i<=n; i++)
        {
            father[i] = i;
            r[i] = 0;
        }
        bool flag = false;
        int fac = 0;
        while(m--)
        {
            scanf("%s",str);
            if(str[0]=='I')
            {
                getchar();
                gets(str);
                fac++;
                int cnt = 0;
                for(i = 0; str[i]!='\0'; i++)
                {
                    if(str[i]==' ')
                        cnt++;
                }
                if(cnt == 1)
                {
                    sscanf(str,"%d%d",&u,&w);
                    v = n;
                }
                else
                {
                    sscanf(str,"%d%d%d",&u,&v,&w);
                }
                if(flag)
                    continue;
                if(!Union(u,v,w))
                {
                    printf("The first %d facts are conflicting.\n",fac);
                    flag = true;
                }
            }
            else
            {
                scanf("%d",&tot);
                for(i = 0; i<tot; i++)
                    scanf("%d",&num[i]);
                if(flag) continue;
                int ans = query();
                if(ans == -1)
                    printf("I don't know.\n");
                else
                    printf("%d\n",ans);

            }
        }
        printf("\n");
    }

    return 0;
}
时间: 2024-11-10 07:14:30

HDU3234&&UVA12232&&LA4487:Exclusive-OR(经典带权并查集)的相关文章

poj1182食物链,经典带权并查集

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类. 第二种说法是"2 X Y",表示X吃Y. 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的.当一句话满足下列三条之一时,这句话就是假话,否

POJ 1984 Navigation Nightmare 【经典带权并查集】

任意门:http://poj.org/problem?id=1984 Navigation Nightmare Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 7783   Accepted: 2801 Case Time Limit: 1000MS Description Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usuall

How Many Answers Are Wrong HDU - 3038 (经典带权并查集)

题目大意:有一个区间,长度为n,然后跟着m个子区间,每个字区间的格式为x,y,z表示[x,y]的和为z.如果当前区间和与前面的区间和发生冲突,当前区间和会被判错,问:有多少个区间和会被判错. 题解:x,y,z表示从x开始到y的所有数字的和,那么x-1就表示从(x-1,y]的区间和.我们可以对区间的左边x-1寻找他的左端点,同时对区间右边y也寻找他的左端点,如果这两个左端点相等(设为l)那么他就是将区间了[l,y]拆分成了[l,x-1]和[x,y],我们判断一下区间和是不是相等的就可以了也就是w[

POJ 1182 食物链(经典带权并查集 向量思维模式 很重要)

传送门: http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 90562   Accepted: 27216 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食

POJ1182 食物链(必做经典带权并查集)

  分析:   本题最重要的是通过向量的想法来解决这一类关系,这样思维难度大大降低,首先我们明白一点   根据传递性的定义(也就是离散数学中的传递性),x->y =x->z+z>y   我们要知道的一点是,并查集中的题目都是有传递性的,而传递性的题目并不一定能通过并查集解决   我们知道我们要将两个不同的集合合并,就是将他们的头结点合并,所以我们需要知道d[pa]的大小是多少   那么我们定义pa->pb的关系就等于 pa->x+x->y+y->pb,其中x-&g

poj 2912(带权并查集)

题意:有n个人玩石头剪刀布的游戏,编号从1到n-1,把所有人分成3组,给每个组分配一个手势(石头.剪子.布),每轮挑出两个人出来进行游戏,这n个人里有一个裁判,他的手势是可以变化的.给出了m轮的游戏结果,a < b表示b赢了a,a = b表示a和b出了同样的手势,问能否找到裁判的编号,是在第几轮发现的. 题解:这题和食物链那个经典带权并查集很像,也可以用0表示父与子是同一种手势,用1表示父大于子,用2表示父小于子.因为裁判的编号不能确定,可以采用枚举的方式,先假定一个人是裁判,然后去掉这个人所有

UVA12232 - Exclusive-OR(带权并查集)

题目:UVA12232 - Exclusive-OR(带权并查集) 题目大意:给你I P V 代表Xp 的值是V.或者 I P Q V 代表X P ^X i + 1 ^X i+2 ...^X^Q = V;然后给你Q k p1 p2 p3...pk问这些数字的异或值. 解题思路:这题首先要明确 x ^ y = V , x ^ z = W, 那么 y ^ z = V ^ W;  所以这题可以用并查集来做,因为只要两个数都和同一个数异或,那么他们就属于同一个集合,这样即使它们和一个数这个数的值是未知的

带权并查集(含种类并查集)【经典模板】 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug&#39;s life(简单) ③hihoCoder 1515 : 分数调查

带权并查集: 增加一个 value 值,并且每次合并和查找的时候需要去维护这个 value 例题一 :POJ 1182 食物链(经典) 题目链接:https://vjudge.net/contest/339425#problem/E 带权并查集的解法 定义两个数组fa[ ]和rela[ ],fa用来判断集合关系,rela用来描述其与根节点的关系.因为关系满足传递性,所以可以推导出给出条件下的当前关系,在判断与之前已有关系是否矛盾. 本题的解法巧妙地利用了模运算,rela数组用0表示同类,1表示当

并查集练习2(带权并查集)

明天旅游去爬山逛庙玩,今天练一天然后早早睡觉啦~ poj1703 Find them, Catch them (带权并查集) 1 #include<cstdio> 2 const int N=1e5+1; 3 int f[N]; 4 int r[N];//表示与父节点的关系,0同类,1不同类 5 int n; 6 void init(){ 7 for(int i=1;i<=n;++i){ 8 f[i]=i; r[i]=0; 9 } 10 } 11 int fin(int x){ 12 i