[la P4487] Exclusive-OR

Time limit 3000 ms  OS Linux

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:

Format Meaning

I p v I tell you Xp = v

I p q v I tell you Xp XOR Xq = v

Q k p1 p2 . . . pk Please tell me the value of Xp1 XOR Xp2 XOR . . . XOR Xpk

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.

很好的一道题目!大力推荐,只是如果认真做,有可能会续掉很长时间。

题目的意思是,给你一系列的操作,有3种形式:

1.I p v 告诉我们Xp=v

2.I p q v 告诉我们Xp^Xq=v

3.Q k p1 p2 ... pk 问我们 Xp1^Xp2^...^Xpk的值。

当然,如果在某个1或2操作时,我们得到的信息与我们已知信息冲突,输出在第几条信息(不包括询问)产生矛盾。

对于每个询问,如果并不能确定答案,输出I don't know.

好的,当我们读懂题目后,就可以思考了。

想一想,这和什么算法或数据结构有关联呢?

这一题我们采用并查集(加权)。

其实我原来想的已经很像正解了,但是由于没有想到“Q”操作,然后就GG了。

好的,我们来讲讲这题怎么用的并查集。

我们用fa[i]表示i的父亲,sum[i]表示从i到i所在的树的根节点,每个点的X值的xor值。

为了便于判断,我们刻意加上一个超级点——0。0的值已知,为0。刚开始的时候,所有节点的父亲都是自己,值未知(为了方便仍设为0)。

则对于1操作:

先判断是否矛盾。怎么样是矛盾的?仅当p的祖先是0时有可能,还要考虑权值。

首先,我们会(或是必要的)进行路径压缩,此时,sum[p]已经更新了,由于fa[p]=0,X[0]=0,所以x[p]=sum[p]。

也就是说,getfa(p)一遍(同时进行路径压缩并正确更新sum),判断v==sum[p]就好了。

如果原来不知道这个信息,则合并fa[p]和0。注意0永远要是一棵树的根节点。

这样的话,sum[getfa(p)]就是sum[p]^v了。

对于操作2,相当于一棵树中的判断或两颗树的合并。

判断的图:

下面p和q的连线可以看做是有向的,不管是上面方向,都应该有sum[p]^sum[q]==v,这就是判断。

合并操作:

应该很明显了吧,用的就是xor的性质,因为sum[q]=v^sum[p]^sum[x],所以sum[x]=sum[p]^sum[q]^v。

注意x不能为0,为0了就和y点swap一下,不可能同时x==0且y==0。

稍微要动一下脑袋的就是“Q”操作。

我们知道,这些给出的点可能是在不同的树里面,但这并不代表不能算出来。

当我们路径压缩后会是这种情况:

这些点的父节点就是根节点,所以不进行区分,就直接说父节点好了。有些点的父节点可能是自己,也可能是其他,还有可能是0。

我们可以把询问的答案变成:

sum[p1]^sum[fa[p1]]^sum[p2]^sum[fa[p2]]^sum[p3]^sum[fa[p3]]^...

那么,由于每一棵树的根节点(除0外)的sum都是0,也就是不知道其权值。

但是,根据xor的性质,一个数xor偶数次就消去了。所以我们判断一下所有非0的fa[px]出现的次数到底是奇数次还是偶数次。

当且仅当出现偶数次,是有解的,解就是sum[p1]^sum[p2]^sum[p3]^...,否则就是I don't know.了。

再注意一下,正确的getfa应该长这样:

 inline int get(int x) {
     if (fa[x]==x) {
         return x;
     }
     int p=fa[x];
     fa[x]=get(fa[x]);
     sum[x]^=sum[p];
     return fa[x];
 }

还有一点,就是把告诉你单点值那个操作归到第2种也是可以的,注意一下无论何时,根为0就行了。

code 1:

 #include <cstdio>
 #include <cstring>
 #include <algorithm>
 #include <iostream>
 ;
 int n,q,len,fa[N],ew[N];
 ],ero,fac,ans,tag;
 ]; bool cnt[N];
 void read() {
     gets(s),len=strlen(s);
     num[]=;
     ; i<len; ++i) {
         ') {
             num[++num[]]=;
         }
         else {
             num[num[]]=num[num[]]*+s[i]-';
         }
     }
     ]=='I') {
         ++fac;
         ]==) {
             ++num[];
         }
         else {
             ++num[]; ++num[];
         }
     }
     else {
         ; i<=num[]; ++i) {
             ++num[i];
         }
     }
 }
 inline int get(int x) {
     if (fa[x]==x) {
         return x;
     }
     int p=fa[x];
     fa[x]=get(fa[x]);
     ew[x]^=ew[p];
     return fa[x];
 }
 int main() {
     ;
     while (scanf("%d%d",&n,&q)!=EOF,n||q) {
         printf(,fac=;
         ; i<=n+; i++) {
             fa[i]=i; ew[i]=;
         }
         fa[]=; ew[]=;
         getchar();
         ; cq<=q; ++cq) {
             read();
             if (ero) {
                 continue;
             }
             ]=='I') {
                 ]==) {
                     x=]);
                     &&ew[num[]]!=num[]) {
                         ero=;
                         printf("The first %d facts are conflicting.\n",fac);
                     }
                     else {
                         x=]);
                         fa[x]=; ew[x]=ew[num[]]^num[];
                     }
                     continue;
                 }
                 x=]),y=]);
                 if (x==y) {
                     ]]^ew[num[]])!=num[]) {
                         ero=;
                         printf("The first %d facts are conflicting.\n",fac);
                     }
                     continue;
                 }
                 ) {
                     std::swap(num[],num[]);
                     std::swap(x,y);
                 }
                 fa[y]=x; ew[y]=ew[num[]]^ew[num[]]^num[];
             }
             else
             ]=='Q') {
                 ans=; tag=;
                 ; i<=num[]; ++i) {
                     x=get(num[i]);
                     ans^=ew[num[i]];
                     num[i]=x;
                     cnt[x]^=;
                 }
                 ; i<=num[]; ++i) {
                     ) {
                         tag=;
                         break;
                     }
                 }
                 ; i<=num[]; ++i) {
                     cnt[num[i]]=;
                 }
                 if (tag) {
                     printf("I don't know.\n");
                 }
                 else {
                     printf("%d\n",ans);
                 }
             }
         }
         putchar('\n');
     }
     ;
 }

code 2:(稍微排布好看了一点qwq)

 #include <cstdio>
 #include <cstring>
 #include <algorithm>
 #include <iostream>
 ;
 int n,q,len,fa[N],sum[N];
 ],ero,fac;
 ]; bool cnt[N];
 void init() {
     gets(s); len=strlen(s); num[]=;
     ; i<len; ++i) {
         ') {
             num[++num[]]=;
         }
         else {
             num[num[]]=num[num[]]*+s[i]-';
         }
     }
     ]=='I') {
         ++fac;
         ]==) {
             num[]=num[]; num[]=++num[]; num[]=;
         }
         else {
             ++num[]; ++num[];
         }
     }else
     ]=='Q') {
         ; i<=num[]; ++i) {
             ++num[i];
         }
     }
 }
 inline int get(int x) {
     if (fa[x]==x) {
         return x;
     }
     int p=fa[x];
     fa[x]=get(fa[x]);
     sum[x]^=sum[p];
     return fa[x];
 }
 int main() {
     ;
     while (scanf("%d%d",&n,&q),n||q) {
         printf("Case %d:\n",++cas);
         fac=; ero=;
         ; i<=n; ++i) {
             fa[i]=i; sum[i]=;
         }
         getchar();
         for (; q; --q) {
             init();
             if (ero) continue;
             ]=='I') {
                 x=]); y=]);
                 ]]^sum[num[]])!=num[]) {
                     ero=;
                     printf("The first %d facts are conflicting.\n",fac);
                     continue;
                 }
                 ) {
                     std::swap(x,y);
                     std::swap(num[],num[]);
                 }
                 fa[y]=x; sum[y]=sum[num[]]^sum[num[]]^num[];
             }else
             ]=='Q') {
                 ans=; tag=;
                 ; i<=num[]; ++i) {
                     x=get(num[i]);
                     ans^=sum[num[i]];
                     num[i]=x;
                     cnt[x]^=;
                 }
                 ; i<=num[]; ++i) {
                     if (cnt[num[i]]&&num[i]) {
                         tag=;
                         break;
                     }
                 }
                 ; i<=num[]; ++i) {
                     cnt[num[i]]=;
                 }
                 if (tag) {
                     printf("I don't know.\n");
                 }
                 else {
                     printf("%d\n",ans);
                 }
             }
         }
         putchar('\n');
     }
     ;
 }

[la P4487] Exclusive-OR的更多相关文章

  1. leggere la nostra recensione del primo e del secondo

    La terra di mezzo in trail running sembra essere distorto leggermente massima di recente, e gli aggi ...

  2. Le lié à la légèreté semblait être et donc plus simple

    Il est toutefois vraiment à partir www.runmasterfr.com/free-40-flyknit-2015-hommes-c-1_58_59.html de ...

  3. ORA-01102: cannot mount database in EXCLUSIVE mode

    安装完ORACEL 10g数据库后,启动数据库时遇到ORA-01102: cannot mount database in EXCLUSIVE mode [oracle@DB-Server ~]$ s ...

  4. Activiti之 Exclusive Gateway

    一.Exclusive Gateway Exclusive Gateway(也称为XOR网关或更多技术基于数据的排他网关)经常用做决定流程的流转方向.当流程到达该网关的时候,所有的流出序列流到按照已定 ...

  5. Mac Pro 使用 ll、la、l等ls的别名命令

    在 Linux 下习惯使用 ll.la.l 等ls别名的童鞋到 mac os 可就郁闷了~~ 其实只要在用户目录下建立一个脚本“.bash_profile”, vim .bash_profile 并输 ...

  6. Linux中的动态库和静态库(.a/.la/.so/.o)

    Linux中的动态库和静态库(.a/.la/.so/.o) Linux中的动态库和静态库(.a/.la/.so/.o) C/C++程序编译的过程 .o文件(目标文件) 创建atoi.o 使用atoi. ...

  7. Mac OS使用ll、la、l等ls的别名命令

    在linux下习惯使用ll.la.l等ls别名的童鞋到mac os可就郁闷了-- 其实只要在用户目录下建立一个脚本“.bash_profile”,并输入以下内容即可: alias ll='ls -al ...

  8. 启动weblogic的错误:Could not obtain an exclusive lock to the embedded LDAP data files directory

    http://hi.baidu.com/kaisep/item/0e4bf6ee5da001d1ea34c986 源地址 启动weblogic的错误:Could not obtain an exclu ...

  9. .Uva&LA部分题目代码

    1.LA 5694 Adding New Machine 关键词:数据结构,线段树,扫描线(FIFO) #include <algorithm> #include <cstdio&g ...

随机推荐

  1. 易爆物D305

    分析:典型的并查集,每一个物品合一看成一个独立的顶点,则一个简单化合物就是一条边,如果两个顶点x,y联通则说明有危险,所以可以用一个并查集来维护图的联通分量集合,并查集的详解有一篇写的很易懂的博客并查 ...

  2. Java第一次实训课

    //1.1 声明一个整型变量a,并赋初值5,在程序中判断a是奇数还是偶数,然后输出判断的结果. package mingye; public class Exc { public static voi ...

  3. CentOS7上手动部署入门级kubernetes

    前言 翻看了很多的kubernetes的安装教程,也反复做了一些实验,深感教程之复杂,所以决定写一个极简版本的安装教程,目标在于用尽可能少的参数启动服务,并且剖析各组件关系,然后再在此基础上逐步添加参 ...

  4. mysql_study_5

    代码 mysql> CREATE TABLE shop ( ) UNSIGNED ZEROFILL ' NOT NULL, ) DEFAULT '' NOT NULL, ,) DEFAULT ' ...

  5. kubernetes集群pod使用tc进行网络资源限额

    kubernetes集群pod使用tc进行网络资源限额 Docker容器可以实现CPU,内存,磁盘的IO限额,但是没有实现网络IO的限额.主要原因是在实际使用中,构建的网络环境是往超级复杂的大型网络. ...

  6. C++隐藏任务栏图标

    在VC编程中,有时候我们需要将我们的程序在任务栏上的显示隐藏起来,我试过几种方法,下面我介绍一下我知道的三种方法. 第一种方法是设置窗口WS_EX_TOOLWINDOW扩展样式,通过在OnInitDi ...

  7. PHP共享内存yac操作类

    http://www.laruence.com/2013/03/18/2846.html   鸟哥介绍 https://www.cnblogs.com/willamwang/p/8918377.htm ...

  8. postgresql开启网络连接

    默认情况下,postgresql是只允许localhost连接的,如果需要使用远程连接,需要修改两个配置文件. postgresql.conf 和 pg_hba.conf 在postgresql.co ...

  9. shell编程(六)之数组

    数组: 存储多个元素的连续的内存空间 索引: 编号从0开始,属于数值索引 注意:索引也可支持使用自定义的格式,而不仅仅是数值格式 声明数组: declare -a ARRAY_NAME declare ...

  10. vue-cli3.0 笔记

      vue-cli 3.0   npm install -g @vue/cli # OR yarn global add @vue/cli ui 界面创建项目 vue ui 命令行创建项目 步骤 vu ...