该死的期末复习终于结束了。。。

暑假来了\color{#ff0000}{暑假来了}暑假来了!!!

所以我就珂以非常开心的写博客了。

原题链接:
hdu

题意简述

多组数据。你有一个没有确定的数列。有一些操作,格式:
I p v第ppp个是vvv(如果某个位置有很多个值,就是矛盾的)
I p q v(没错也是I,所以要用sscanf判一下空格数量)第ppp个异或第qqq个为vvv(这个异或值也可能会有矛盾)
Q k p1 p2 ... pk求p1,p2...pkp1,p2...pkp1,p2...pk的异或和(如果无法确定输出I don't know.
处理以上操作时,如果有矛盾的,输出
The first i facts are conflicting.(iii为第一个矛盾的操作编号),然后忽略这组数据以下的赋值操作和询问操作。

数据

输入

多组数据。以0 0结束。
每组数据:

n m
//数列长度,操作个数(n<=20000,m<=40000)
operation
//一个操作,格式如上
输出
Case #i:
ans
ans
...
ans
//(ans=一个整数,I dont't know或者The first i facts are conflicting.)
样例

输入

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

输出

Case 1:
I don't know.
3
1
2
Case 2:
4
Case 3:
7
The first 2 facts are conflicting.

思路

(注:题目中是000编号,我就被掰弯了,也是000编号。)
(111编号了那么久。。。)

这个题。。。没做过的话,真的不会想到用并查集做。。。

我们维护一个并查集,带权,其中权值用XorXorXor数组表示,Xor[i]Xor[i]Xor[i]是iii和iii父亲的异或值。
那么,我们不是要资瓷路径压缩的么。。。怎么压缩捏。。。

part1. 找祖先(Find函数),带路径压缩

设fa[i]fa[i]fa[i]为iii的父亲,aaa是那个要确定的序列,⊕\oplus⊕是异或
我们只要能把Xor[i]Xor[i]Xor[i]用O(1)O(1)O(1)的复杂度从原本的
a[i]⊕a[fa[i]]a[i] \oplus a[fa[i]]a[i]⊕a[fa[i]]
变成
a[i]⊕a[fa[fa[i]]]a[i] \oplus a[fa[fa[i]]]a[i]⊕a[fa[fa[i]]]。
我们会发现,Xor[fa[i]]=a[fa[i]]⊕a[fa[fa[i]]]Xor[fa[i]]=a[fa[i]]\oplus a[fa[fa[i]]]Xor[fa[i]]=a[fa[i]]⊕a[fa[fa[i]]]
我们用Xor[i]Xor[i]Xor[i]异或Xor[fa[i]]Xor[fa[i]]Xor[fa[i]],那么Xor[fa[i]]Xor[fa[i]]Xor[fa[i]]就被异或了两次,也就是没了(众所周知异或同一个数两次相当于没异或)。所以,我们只要Xor[i]⊕=Xor[fa[i]]Xor[i]\oplus=Xor[fa[i]]Xor[i]⊕=Xor[fa[i]],就珂以一步一步把Xor[i]Xor[i]Xor[i]设置为a[i]⊕a[ancestor]a[i]\oplus a[ancestor]a[i]⊕a[ancestor]了(其中ancestorancestorancestor是祖先),就实现了路径压缩。
写出代码:

int Find(int x)
{if (x!=Father[x]){int fa=Father[x];Father[x]=Find(Father[x]);Xor[x]^=Xor[fa];}return Father[x];
}//说了这么多,代码很水,注意不要写挂即可。
此时,路径压缩完了,Xor[]Xor[]Xor[]的定义变为:Xor[i]Xor[i]Xor[i]是iii和iii祖先的异或值。注意。

那么。。。合并捏?

part2. 合并(Merge函数)

假设我们要设置a[x]⊕a[y]=ca[x]\oplus a[y]=ca[x]⊕a[y]=c(就是第二个操作)。所以我们就要合并xxx和yyy。设xxx的祖先是axaxax,yyy的祖先是ayayay。

  1. 首先要判矛盾。如果ax==ayax==ayax==ay,说明xxx和yyy在同一个集合。此时他们的祖先是共有的,那么Xor[x]⊕Xor[y]Xor[x]\oplus Xor[y]Xor[x]⊕Xor[y]就是a[x]⊕a[y]a[x]\oplus a[y]a[x]⊕a[y](祖先被异或了两次,抵消了)
    如果这个值不等于ccc,那就爆了,就是有矛盾的。我们给合并函数设置一个boolboolbool类型的返回值,如果出现了矛盾,返回falsefalsefalse,否则返回truetruetrue。
  2. 那么如果没有出现矛盾,我们就只能乖♂乖♂合并了。我们假设要把axaxax接到ayayay上。原本的Xor[ax]Xor[ax]Xor[ax]肯定是000(想一想Xor[]Xor[]Xor[]的定义。然后axaxax又是一个祖先,祖先和祖先的祖先(也就是自己)异或一下,那就是000了)。但是现在我们要把它设置成a[ax]⊕a[ay]a[ax]\oplus a[ay]a[ax]⊕a[ay]。怎么办呢。。。
    我们发现a[x]⊕a[y]a[x]\oplus a[y]a[x]⊕a[y]是知道的,它等于ccc(这是题目的要求)。我们现在以数学竞赛生的角度去破解这个玩意。因为有a[ax]a[ax]a[ax]这个项,我们的已知数里面,哪个包含这个项呢?那当然是Xor[x]Xor[x]Xor[x],它等于a[x]⊕a[ax]a[x]\oplus a[ax]a[x]⊕a[ax]。同理,我们还需要一个Xor[y]Xor[y]Xor[y]项,尝试把这两个东西异或起来,等于:
    (a[ax]⊕a[ay])⊕(a[x]⊕a[y])(a[ax]\oplus a[ay]) \oplus (a[x]\oplus a[y])(a[ax]⊕a[ay])⊕(a[x]⊕a[y])
    =(a[ax]⊕a[ay])⊕c=(a[ax]\oplus a[ay]) \oplus c=(a[ax]⊕a[ay])⊕c
    我们发现,此时再把ccc给异或掉,我们就求出来我们要的那个东西了!!!
    此时,写出代码:
bool Merge(int x,int y,int c)
{int ax=Find(x),ay=Find(y);if(ax==ay){if((Xor[x]^Xor[y])!=c) return false;return true;}if(ax==n) swap(ax,ay);Father[ax]=ay;Xor[ax]=Xor[x]^Xor[y]^c;//核心return true;
}//同样,也就是思维难度大,代码不长

part3. 如何用这个并查集

  1. 对于111操作:我们设置一个临时节点nnn(注意原来的aaa数组中是000到n−1n-1n−1,是没有nnn这个点的)。令a[n]=0a[n]=0a[n]=0。那么这个赋值操作a[p]=v就相当于a[p]^a[n]=0,转化为222操作
  2. 板子。直接套并查集
  3. 我们把询问中的这些数分成若干块,同一块里边祖先相等(即在同一个联通块内)。计算是否把祖先异或了偶数次。因为异或两次是珂以抵消的,所以异或偶数次也就珂以抵消了。然后把该块内的XorXorXor值异或起来,因为祖先被抵消了,所以就变成了aaa的异或和。(如果祖先是nnn,由于a[n]=0a[n]=0a[n]=0,不管异或了奇数次还是偶数次,都不会有变化。此时也是珂以求出联通块的答案的。)然后把每一块的答案都异或起来,就是这kkk个数的异或和。但是注意,只要有一个块是未知的,那么我们就求不出答案。

好了这个题就做完了。代码:

#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{#define N 20005int n,q,k;int nums[N],vis[N];char tmp[110];class DSU{public:int Father[N];int Xor[N];int Find(int x){if (x!=Father[x]){int fa=Father[x];Father[x]=Find(Father[x]);Xor[x]^=Xor[fa];}return Father[x];}bool Merge(int x,int y,int c){int ax=Find(x),ay=Find(y);if(ax==ay){if((Xor[x]^Xor[y])!=c) return false;return true;}if(ax==n) swap(ax,ay);Father[ax]=ay;Xor[ax]=Xor[x]^Xor[y]^c;return true;}}D;//毒瘤并查集int Query(){int smcnt,ans=0;memset(vis,0,sizeof(vis));for(int i=0;i<k;++i){if (vis[i]) continue;smcnt=0;int ai=D.Find(nums[i]);//祖先for(int j=i;j<k;++j){if (!vis[j] and ai==D.Find(nums[j])/*有相同的祖先*/)//查找同一个块内的数{vis[j]=1;++smcnt;//同一个块内有多少元素(是same count的简写)ans^=D.Xor[nums[j]];//每个Xor值异或起来}}if ((smcnt&1) and ai!=n)//此时是无解的情况{return -1;}}return ans;}void Soviet(int Case){int u,v,w;printf("Case %d:\n",Case);int fact=0;bool flag=0;//记录有没有矛盾while(q--){scanf("%s",tmp);if (tmp[0]=='I'){getchar();//会有一个多余的空格(在I和剩下的操作之间)gets(tmp);++fact;int spacecnt=0;for(int i=0;tmp[i]!='\0';++i){if (tmp[i]==' '){++spacecnt;}}if (spacecnt==1){sscanf(tmp,"%d%d",&u,&w);v=n;}else{sscanf(tmp,"%d%d%d",&u,&v,&w);}if (flag) continue;if (!D.Merge(u,v,w)){printf("The first %d facts are conflicting.\n",fact);flag=1;}}else{scanf("%d",&k);for(int i=0;i<k;++i){scanf("%d",&nums[i]);}if (flag) continue;int ans=Query();if (ans==-1){printf("I don't know.\n");}else{printf("%d\n",ans);}}}putchar('\n');}void IsMyWife(){int Case=1;while(~scanf("%d%d",&n,&q),n+q){for(int i=0;i<=n;i++){D.Father[i]=i;D.Xor[i]=0;}Soviet(Case++);}}
}int main()
{Flandle_Scarlet::IsMyWife();return 0;
}

回到总题解界面

hdu 3234 Exclusive-OR 题解(并查集,思维)相关推荐

  1. HDU 1272 小希的迷宫 (并查集)

    小希的迷宫 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submiss ...

  2. How Many Answers Are Wrong HDU - 3038(带权并查集经典题,满满的都是注释)

    How Many Answers Are Wrong HDU - 3038  点击打开链接 题意:现在有n个数(你并不知道这n个数是什么),m次查询,每次查询给出u,v,w.表示从第u个数到第v个数的 ...

  3. hdu 1232 畅通工程 最小生成树 并查集

    1232的连接:http://acm.hdu.edu.cn/showproblem.php?pid=1232 #include <iostream>#include <cstdio& ...

  4. hdu 3461 Code Lock(并查集)2010 ACM-ICPC Multi-University Training Contest(3)

    想不到这还可以用并查集解,不过后来证明确实可以-- 题意也有些难理解-- 给你一个锁,这个所由n个字母组成,然后这个锁有m个区间,每次可以对一个区间进行操作,并且区间中的所有字母要同时操作.每次操作可 ...

  5. HDU 1213 How Many Tables 并查集 水~

    http://acm.hdu.edu.cn/showproblem.php?pid=1213 果然是需要我陪跑T T,禽兽工作人员还不让,哼,但还是陪跑了~ 啊,还有呀,明天校运会终于不用去了~耶耶耶 ...

  6. hdu 1811 Rank of Tetris (并查集+拓扑排序)

    Problem - 1811 感觉这题的并查集以及拓扑排序并不难,但是做题的时候必须理解到矛盾(CONFLICT)与不确定(UNCERTAIN)直接的优先关系. 做这题的时候,构图什么的很简单,就是没 ...

  7. PAT甲级1118 Birds in Forest :[C++题解]并查集

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析:并查集的合并和查询. 问:一张照片上的鸟如何合并?相邻的合并(笔者采用的方式)或者全合并到第一只鸟就行,遍历一遍.所有照片中的鸟,合并 ...

  8. PAT甲级1013 Battle Over Cities:[C++题解]并查集、结构体存边

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析:并查集题目. 不清楚并查集的小伙伴,请移步并查集原理并查集板子:acwing836. 合并集合. 题意:给定一个连通图,当删掉任意1个 ...

  9. hdu 3047 Zjnu Stadium(并查集)

    题意: 300个座位构成一个圈. 有N个人要入座. 共有M个说明 :A B X ,代表B坐在A顺时针方向第X个座位上.如果这个说明和之前的起冲突,则它是无效的. 问总共有多少个无效的. 思路: 并查集 ...

  10. HDU - 2874 Connections between cities(并查集+LCA)

    题目链接:点击查看 题目大意:给出n个点代表城市,再给出m条边将其连接,每条边都有边权,题目保证给出的图无环,现在给出两个点,首先询问两个点是否互相连通,若可以连通,询问两点之间的距离 题目分析:判断 ...

最新文章

  1. Flask rst 文档转换为html格式文件
  2. API 23之前的版本都是自动获取权限,而从 Android 6.0 开始添加了权限申请的需求,更加安全。
  3. Solaris 9安装VNC
  4. java多表查询返回数据_spring data jpa如何在多张数据库表中查询返回某些字段值?...
  5. C#调用C++类(以COM组件的形式)
  6. 新泰一中2021年高考成绩查询,牛!泰安新泰一中2018年高考一班级62人全部上本科线...
  7. 运用C#在采集时进行自动验证登录[转]
  8. MySQL 解压版和安装版的安装
  9. nltk 句子结构分析
  10. 前端性能优化方案(图片)
  11. 通过股票数据接口如何看懂Level-2行情?
  12. 图解HTTP(笔记)
  13. 无论被多少人喷,《王牌战士》这次真的火了吗?
  14. ASP是什么?ASP初识
  15. python与开源gis_GitHub - geodoer/GISandPython: 开源GIS与Python
  16. RVB2601开发板试用3——以太网通讯测试
  17. 苹果电脑win10蓝牙音响卡顿_如何修复Windows 10蓝牙扬声器的声音延迟问题
  18. 腾讯十大开源项目,最后一个太受欢迎了!
  19. 计算机access和office,计算机二级access和office
  20. 电话面试经历 - 负暄琐话 - CSDNBlog

热门文章

  1. 春运首日 民航局在10个机场开展国内航班夜航试点
  2. 北京安居客二手房信息爬取
  3. Think - 我思故我在
  4. [手机分享]黑莓手机7系列分享之——7100T
  5. inventor2五子棋游戏apk_联机五子棋手机版下载|联机五子棋游戏下载v1.3.2 安卓版_ 单机手游网...
  6. Mathtp**下载
  7. 网络安全(三 漏洞的抓取与挖掘)
  8. YXCMS靶场实验报告
  9. cortex A8/A9/A5/A15 智能手机名称整理
  10. 设计师学python有意义吗-如果你有设计师朋友,请对TA好一些...