P3762守夜人
问题描述
鉴于john snow当选了新的守夜人总司令,艾里沙爵士感觉非常不爽,想搞点事情来难倒snow。艾里沙爵士告诉你有一个n项的序列X0,X1,X2…..Xn-1。(其中每一项均在int范围之内)但是你现在不知道其中的任何一项。艾里沙会逐步的告诉你一些信息并且问你一些问题。共有两种类型的信息和一种类型的询问。
I p v : 告诉你 Xp = v
I p q v : 告诉你 Xp XOR Xq = v
Q k p1 p2 . . . pk : 询问Xp1 XOR Xp2 XOR . . . XOR Xpk的值 k≤15
输入格式
会有多组测试数据但不会超过10组。
每一组数据以两个整数开始:n , Q(1 ≤ n ≤ 20, 000, 2 ≤ Q ≤ 40, 000)题目描述中的k是一个不大于15的整数。
最后一组数据为n==Q==0,不用进行运算。
输出格式
对于每组数据,输出第一行为数据的组数,接下来的每一行对应一次询问的答案。
如果根据前面给出的信息无法算出答案,则输出“I don’t know.”。
如果与已知信息冲突,输出“The first i facts are conflicting.”,并结束对于这一组数据的运算,其中i为这组数据出现过的的信息条数(不含询问,包含当前这一条信息)。
样例输入
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.
提示
注释:
鉴于两种I操作的输入比较麻烦,这里给出一种参考输入方法:
gets(s);
if(sscanf(s,”%d%d%d”,&a,&b,&v)==2)
//这一行输入了两个整数,要先除去行首的字母,具体可参考代码
这题显然是带权并查集,用$D[i]$来记录下$i$和的他父亲的异或值。考虑如何处理三个操作。
先处理路径压缩,假设fx是x的父亲,ffx是fx的父亲,由异或运算的特性可知x^ffx=x^fx^fx^ffx=D[x]^D[fx],所以路径压缩就解决了。
考虑已知$x_p$^$x_q=v$,那么合并p,q所在集合,令fp是p的根,fq是q的根,那么将fq设为fp的父亲,有D[fp]=fp^fq=p^fp^q^fq^p^q=D[p]^D[q]^v,所以合并操作解决。
然后问题是处理操作一,这里有两种处理办法,一种是添加虚拟节点,将操作一视为操作二,并保证虚拟节点永远是根。具体可以参考THH的博文。
我用的是第二种操作,直接用数组X[i]记录下他的值即可,然后为了维护X[i],需要将路径压缩中添加一步,即如果父亲的X值已知,那么就顺便把儿子的X值算出来,因为知道他们的异或和。同时合并时要优先将X值已知的元素作为父亲。
然后考虑如何判断矛盾,关于操作一,那么只需要和X数组比较一下即可。对于操作二稍复杂,我们需要判断两种情况:
1.给出的两个数p,q位于同一集合,那么判断给出的值是否等于D[p]^D[q]。
2.p,q不在同一集合,那么判断是否两个数的X值都已知,如果都已知就判断给出的值是否等于X[p]^X[q]
最后处理询问操作,首先将询问的k个元素中已知的元素找出来并标记,直接异或到ans中,然后处理未知的元素,这些未知的元素必然要两两配对异或起来,因此直接暴力找位于同一集合的元素异或起来并异或到答案中,如果有不能配对的元素,那么就得不到答案,如果都配对的,就找到了。这里写的时候优化一下可以$O(k)$解决。
代码:
1 |
|