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

这个题目用加权并查集是这么处理的:

1. f[]照样是代表父节点,照样进行路径压缩,把每个 V[i]=V[i]^V[f[i]],即节点存储的值实际是它与它父亲的异或的值。为什么要这样呢,因为异或首先满足交换律,而且异或同一个数偶数次,即相当于本身,那么这个题目的其中一个要求是探测冲突,则如果两个点同属一个集合,那么 他们的 Xp^Xq=Xp^Xf^Xq^Xf=v[p]^v[q],就是利用了异或偶数次等于本身的原理,在真正计算的时候,也是这样,只有父节点被异或了偶数次 才可以被消除,求得真正的值,只有其中有一个或者以上的父节点经过了奇数次的异或,说明根本就求不出来,输出 I don't know.

2.为了应对I P V 这种直接赋值的做法,人为添加一个超级父节点T,v[T]=0每次让它跟T来异或,这样就不用特殊处理了

3.每次合并的时候,T一定要是父节点,特判一下。find的时候,进行路径压缩,同时对加权进行合并,通过异或偶数等于本身的特性,将底下的节点顺利的转化为父节点的子节点。

4.注意一下 !运算的优先级高于^,为了这个WA了几次,以后涉及位运算的,多写括号,感觉不是第一次被优先级给坑了。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = +;
int f[N],v[N];
int vis[N],a[];
int T=N-;
void init(int n)
{
for (int i=;i<=n+;i++){
f[i]=i;
v[i]=;
vis[i]=;
}
f[T]=T;
v[T]=;
}
int findset(int x)
{
if (x!=f[x]){
int tmp=f[x];
f[x]=findset(f[x]);
v[x]^=v[tmp];//因为v[x]本身就包括了异或上一层父节点的值,此时与上一层再异或一次,就抵消了
}
return f[x];
}
bool uset(int p,int q,int val)
{
int r1=findset(p);
int r2=findset(q);
if (r1==r2){
if ((v[p]^v[q])!=val) return ;
else return ;
}
if (r1==T) swap(r1,r2);
f[r1]=r2;
v[r1]=v[p]^v[q]^val;//这里要注意,实际V[r1]=xr1^xr2,而Vp和Vq包含这两项,并且用val把他们自身给抵消了,就剩下那两项了,异或确实是很奇妙
return ;
}
int main()
{
int n,Q,p,q,val,kase=;
char ch[];
char s[];
while(scanf("%d%d",&n,&Q))
{
if (!(n+Q)) break;
init(n);
printf("Case %d:\n",++kase);
bool err=;
int facts=;
for (int i=;i<=Q;i++){
scanf("%s",ch);
if (ch[]=='I'){
facts++;
gets(s);
if (sscanf(s,"%d%d%d",&p,&q,&val)==) {
val=q;q=T;
}
//cout<<p<<" "<<q<<" "<<val<<endl;
if (err) continue;
if (!uset(p,q,val)){
printf("The first %d facts are conflicting.\n",facts);
err=;
}
}
else {
int k,ans=;
scanf("%d",&k);
for (int i=;i<=k;i++){
scanf("%d",&a[i]);
if(err) continue;
int r=findset(a[i]);
ans^=v[a[i]];
a[i]=r;
vis[r]^=;
}
if (err) continue;
bool flag=;
for (int i=;i<=k;i++){
if (vis[a[i]]){//这里判断是否是奇数次
if (a[i]!=T){//如果奇数次是超级父节点,没关系,因为他的值已知
flag=;
}
vis[a[i]]=;
}
}
if (flag) printf("%d\n",ans);
else printf("I don't know.\n");
}
}
puts("");
}
return ;
}

UVALive 4487 Exclusive-OR 加权并查集神题的更多相关文章

  1. hdu 3047 Zjnu Stadium(加权并查集)2009 Multi-University Training Contest 14

    题意: 有一个运动场,运动场的坐席是环形的,有1~300共300列座位,每列按有无限个座位计算T_T. 输入: 有多组输入样例,每组样例首行包含两个正整数n, m.分别表示共有n个人,m次操作. 接下 ...

  2. hdu 3635 Dragon Balls(加权并查集)2010 ACM-ICPC Multi-University Training Contest(19)

    这道题说,在很久很久以前,有一个故事.故事的名字叫龙珠.后来,龙珠不知道出了什么问题,从7个变成了n个. 在悟空所在的国家里有n个城市,每个城市有1个龙珠,第i个城市有第i个龙珠. 然后,每经过一段时 ...

  3. HDU 3407.Zjnu Stadium 加权并查集

    Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  4. A Bug's Life(加权并查集)

    Description Background  Professor Hopper is researching the sexual behavior of a rare species of bug ...

  5. A Bug's Life(加权并查集)

    Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs ...

  6. P1196 银河英雄传说(加权并查集)

    P1196 银河英雄传说 题目描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦 创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在 ...

  7. Zjnu Stadium(加权并查集)

    Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  8. 洛谷 P2024 [NOI2001]食物链(种类并查集,加权并查集)

    传送门 解题思路 加权并查集: 什么是加权并查集? 就是记录着每个节点到它的父亲的信息(权值等). 难点:在路径压缩和合并节点时把本节点到父亲的权值转化为到根节点的权值 怎么转化呢? 每道题都不一样Q ...

  9. 牛客网-Beauty of Trees 【加权并查集】

    锟斤拷锟接o拷https://www.nowcoder.com/acm/contest/119/A锟斤拷源锟斤拷牛锟斤拷锟斤拷 锟斤拷目锟斤拷锟斤拷 It锟斤拷s universally acknow ...

随机推荐

  1. C# 自定义控件容器,设计时可添加控件

    本分步指南介绍在将 UserControl 放在 Windows 窗体上之后,如何将 UserControl 对象用作设计时控件容器.可能会有这样的情况:您想将一个控件拖到 UserControl 中 ...

  2. 【剑指Offer】面试题34. 二叉树中和为某一值的路径

    题目 输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径.从树的根节点开始往下一直到叶节点所经过的节点形成一条路径. 示例: 给定如下二叉树,以及目标和 sum = 22, 5 / ...

  3. 第1节 IMPALA:2、架构介绍

    impala的架构以及查询计划: impalad :从节点 对应启动一个impala-server的进程 ,主要负责各种查询计划,官方建议与所有的datanode安装在同一台机器上面 impala-s ...

  4. C++面试常见问题——14内存管理

    内存管理 内存管理由三种方式: 自动存储 静态存储 动态存储 自动存储 对于函数的形参.函数内部变量.和结构体变量等,编译器在函数运行过程中在栈中自动对其分配内存,调用结束后对其进行销毁.变量的声明周 ...

  5. python 字符串实例:检查并判断密码字符串的安全强度

    检查并判断密码字符串的安全强度 import string def check(pwd): #密码必须至少包含六个字符 if not isinstance(pwd,str) or len(pwd)&l ...

  6. ubuntu14安装一些常用的软件

    1.搜狗输入法: 2.sublime 3. 搜狗输入法在Linux里面还是很正常的,并没有想在windows下那样充斥这各种广告. 在搜狗的官网下载了输入法-->双击安装-->提示存在依赖 ...

  7. Metasploit学习笔记——情报搜集技术(只记录与metasploit有关的)

    1.外围信息搜集 1.1whois域名注册信息查询 示例代码如下 msf > whois testfire.net 1.2网站的目录结构 示例代码如下 msf > use auxiliar ...

  8. Vue(九)---自定义指令(directive )

    1.无参数 自定义指令的方式:1. 使用Vue.directive 来自定义2. 第一个参数就是 指令名称 xart3. el 表示当前的html dom对象4. 在方法体内就可以通过 innerHT ...

  9. leetcode1161 Maximum Level Sum of a Binary Tree

    """ BFS遍历题,一遍AC Given the root of a binary tree, the level of its root is 1, the leve ...

  10. Java If ... Else

    章节 Java 基础 Java 简介 Java 环境搭建 Java 基本语法 Java 注释 Java 变量 Java 数据类型 Java 字符串 Java 类型转换 Java 运算符 Java 字符 ...