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]D[i]来记录下ii和的他父亲的异或值。考虑如何处理三个操作。

先处理路径压缩,假设fx是x的父亲,ffx是fx的父亲,由异或运算的特性可知x^ffx=x^fx^fx^ffx=D[x]^D[fx],所以路径压缩就解决了。

考虑已知xpx_p^xq=vx_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)O(k)解决。


代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 43333
using namespace std;
int n,m,F[N],X[N],V[N],A[20];
bool mark1[20],mark2[20];
char s[N];
int GF(int x)
{if(F[x]==x)return x;int t=F[x];F[x]=GF(F[x]);if(X[t]!=-1)X[x]=V[x]^X[t];//更新X值V[x]^=V[t];//更新V值return F[x];
}
int main()
{int i,j,a,b,v,p,q,cnt,k,o,fx,fy,pp,T=0,ans;scanf("%d%d",&n,&m);while(n!=0){printf("Case %d:\n",++T);for(i=1;i<=n;i++)F[i]=i,V[i]=0,X[i]=-1;cnt=0;for(i=1;i<=m;i++){scanf("%s",s);if(s[0]=='I'){cnt++;gets(s);if(sscanf(s,"%d%d%d",&a,&b,&v)==2){a++;p=GF(a);if(X[a]!=-1&&b!=X[a]){printf("The first %d facts are conflicting.\n",cnt);break;}X[a]=b;F[a]=a;F[p]=a;//把他设为所在集合的根V[p]=V[a];V[a]=0;continue;}a++;b++;p=GF(a);q=GF(b);if(X[a]!=-1&&X[b]!=-1){if((X[a]^X[b])!=v){printf("The first %d facts are conflicting.\n",cnt);break;}}if(p==q){if((V[a]^V[b])!=v){printf("The first %d facts are conflicting.\n",cnt);break;}}if(X[p]!=-1)swap(p,q);//优先将X值已知的元素作为根F[p]=q;V[p]=V[a]^V[b]^v;}else{gets(s);o=sscanf(s,"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",&k,&A[1],&A[2],&A[3],&A[4],&A[5],&A[6],&A[7],&A[8],&A[9],&A[10],&A[11],&A[12],&A[13],&A[14],&A[15]);//智障的读入memset(mark1,0,sizeof(mark1));pp=0;ans=0;for(j=1;j<=k;j++)A[j]++,GF(A[j]);for(j=1;j<=k;j++)if(X[A[j]]==-1&&mark1[j]==0)//未知元素{fx=GF(A[j]);ans^=V[A[j]];mark1[j]=1;o=1;for(p=1;p<=k;p++)if(X[A[p]]==-1&&mark1[p]==0){fy=GF(A[p]);if(fx==fy){o++;ans^=V[A[p]];mark1[p]=1;}}if(o&1){pp=1;break;}//一个集合中可以一次处理完}else if(mark1[j]==0)ans^=X[A[j]],mark1[j]=1;//已知元素if(pp){printf("I don't know.\n");continue;}printf("%d\n",ans);}}while(i<m){gets(s);i++;}scanf("%d%d",&n,&m);}
}

NKOJ 3762 守夜人 (并查集)相关推荐

  1. 并查集c++代码_[Leetcode 每日精选](本周主题-并查集) 547. 朋友圈

    题目难度: 中等 原题链接 今天继续来做并查集的问题, 这道题仍然比较基础, 而且也是个比较接近现实的问题了. 大家在我的公众号"每日精选算法题"中的聊天框中回复 并查集 就能看到 ...

  2. HDU1811 Rank of Tetris 拓扑排序+并查集 OR 差分约束最短路+并查集

    题目链接 题意:就是给你一堆关系,看能不能排出个确定的顺序 做法: 1. 拓扑排序+并查集 应该很容易想到的一种思路,大于小于建立单向边.对于相等的呢,就把他们缩成一个点.就用并查集缩成一个点就行了 ...

  3. HDU 2586 How far away ? LCA ---tanjar+并查集 离线算法

    tanjar算法离线求LCA的思想主要是利用并查集的思想. 求距离的话就是d[start[i]]+end[en[i]]-2*d[lca[i]]; 首先从根节点dfs,在深度遍历的回溯的过程中不断的更新 ...

  4. POJ - 2513 Colored Sticks 欧拉通路+并查集+静态树

    一开始想用map来搞,但是感觉好复杂,然后想了一下看大佬们用trie做的,感觉十分合理就敲了一发. 一开始re,数组要开到550000 只会静态的字典树,在每个根节点看是否出现过改颜色,如果没有就把该 ...

  5. 关于 并查集(union find) 算法基本原理 以及 其 在分布式图场景的应用

    二月的最后一篇水文-想写一些有意思的东西. 文章目录 环检测在图数据结构中的应用 深度/广度优先 检测环 并查集数据结构 (Union-Find) 基本概念 初始化 合并 union 查找祖先 优化1 ...

  6. 【BZOJ1015】【JSOI2008】星球大战 并查集

    题目大意 给你一张\(n\)个点\(m\)条边的无向图,有\(q\)次操作,每次删掉一个点以及和这个点相邻的边,求最开始和每次删完点后的连通块个数. \(q\leq n\leq 400000,m\le ...

  7. 并查集 HDOJ 1232 畅通工程

    题目传送门 1 /* 2 并查集(Union-Find)裸题 3 并查集三个函数:初始化Init,寻找根节点Find,连通Union 4 考察:连通边数问题 5 */ 6 #include <c ...

  8. 1013 Battle Over Cities(并查集解法)

    关于背景的介绍见1013 Battle Over Cities(图的DFS解法) DFS就是不算特定结点后数连通子图的总数,再减一.我想着那么并查集就是数不算特定节点后,集合元素(根)的个数.但是我弄 ...

  9. 并查集专题练习:好朋友(未完待续)

    有空再把题目补上 输入样例1 4 2 1 4 2 3 样例输出1 2 输入样例2 7 5 1 2 2 3 3 1 1 4 5 6 输出样例2 3 解题思路: 1. 这题放在并查集的专题后面,有查找也有 ...

最新文章

  1. 什么是软件定义数据中心
  2. Kubernetes 容器网络模型和典型实现
  3. markdown怎么输入指数、幂、次方、上下标?(2^8^=256、a~0~=1)
  4. windbg检测句柄泄露(定位到具体代码)
  5. 中国最为著名的古塔,你认识几座?
  6. LeetCode 356. 直线镜像
  7. 【LeetCode笔记】剑指 Offer 10-I. 斐波那契数列 (Java、递归、动态规划)
  8. 2021安徽舒城中学高考成绩查询,2021安徽省地区高考成绩排名查询,安徽省高考各高中成绩喜报榜单...
  9. Win7的电脑屏幕如何优化设置
  10. 2017 开源软件排行_2017年面向设计师和艺术家的顶级开源解决方案
  11. DPDK在Linux用户级执行环境中执行EAL
  12. 看这篇就够了!一文读懂拜占庭将军问题
  13. 暑假NOIP期末考试【1】—— Phantom
  14. 读论文 + 总结 + 笔记
  15. Java开发实用的面试题及参考答案
  16. 优秀LOGO设计的规则
  17. 2020.8.11贝壳找房笔试复盘
  18. 关于plist文件存储方式(swift)
  19. real——表单样式
  20. 计算机算法发展史文献,多舛的创新历程:国内结构分析软件发展历程之高校篇...

热门文章

  1. 微信小程序体验版ios白屏 安卓报错 {“errMsg“:“hideLoading:fail:toast can‘t be found“}
  2. ucos OS_ENTER_CRITICAL .
  3. chrome performance性能检测面板
  4. 微信公众平台开发(11)--用户管理,获取关注用户的信息
  5. 智慧图书馆解决方案-最新全套文件
  6. 什么是udp攻击?udp攻击的基本原理是什么
  7. Python黑客攻防入门
  8. 微信事件推送原理猜想与小程序接口对接经验之谈(即时配送)
  9. Phython基础笔记
  10. ESP8266给服务器发送数据