【NOI 2015】程序自动分析 并查集与离散化处理
题目描述
在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设x1,x2,x3,…代表程序中出现的变量,给定n个形如xi=xj或xi≠xj的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:x1=x2,x2=x3,x3=x4,x1≠x4,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。
输入
输入文件的第1行包含1个正整数t,表示需要判定的问题个数。注意这些问题之间是相互独立的。
对于每个问题,包含若干行:
第1行包含1个正整数n,表示该问题中需要被满足的约束条件个数。
接下来n行,每行包括3个整数i,j,e,描述1个相等/不等的约束条件,相邻整数之间用单个空格隔开。若e=1,则该约束条件为xi=xj;若e=0,则该约束条件为xi≠xj。
输出
输出文件包括t行。
输出文件的第k行输出一个字符串“YES”或者“NO”(不包含引号,字母全部大写),“YES”表示输入中的第k个问题判定为可以被满足,“NO”表示不可被满足。
测试输入
2
2
1 2 1
1 2 0
2
1 2 1
2 1 1
测试输出
NO
YES
提示
在第一个问题中,约束条件为:x1=x2,x1≠x2。这两个约束条件互相矛盾,因此不可被同时满足。
在第二个问题中,约束条件为:x1=x2,x2=x1。这两个约束条件是等价的,可以被同时满足。
1≤n≤1000000
1≤i,j≤1000000000
题目分析
对于本题,目的是判断程序能否满足所有的输入,因为只有相同和不同两种关系,那么我们可以先处理所有的相同的关系,将相同的数对用并查集维护成一个个不相交集合或者相交集合,而后再处理不同的数对,一旦不同的数对在同一个集合中则发生矛盾,输出NO即可,遍历完所有的不同数对发现确实都属于不同的集合则输出YES,本题需要注意的是输入数字较大,需要用离散化进行处理,直接开数组是不行的
注意点
- 关于并查集的建立,本题由于数据量很大,所以需要用到路径压缩,注释的部分是不采用路径压缩时的代码,路径压缩目的能使一个集合在与另一个集合合并前是以一棵深度只有1的树,这样减少了部分查询的消耗(数据量大的时候更为明显)
int find(int x){
if(p[x] == x) return x;
else{
p[x] = find(p[x]);
}
return p[x];
// while(p[x] != x){
// x = p[x];
// }
// return x;
}
- 关于C++ STL中的unique()函数,它的作用是对一个已经排序完成的数组,实现“合并”相邻的相同数字,为什么合并要带引号呢?事实上,合并后的数组长度未发生变化,它合并的过程是不断把后面的元素覆盖前面重复元素(具体就不作讲解了),在对数组执行unique操作时,一般接受两个参数,数组的首地址和尾地址,而它的返回值是完成查重后的数组的有序位最后一个+1的引用,就是说数组1,1,2,2,4,5,5,6通过unique(a, a+8)之后数组就变成了1,2,4,5,6,5,5,6只有前5个是有序的,且int t = unique(a, a+8)存放的是a[5]的引用,所以如果想得到具体是第几个那么我们一般写成int t = unique(a, a + 8) - a;那么t自然而然就是5,下面是代码
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int main(){
int a[] = {1, 1, 2, 2, 4, 5, 5, 6};
int t = unique(a, a + 8) - a;
cout<<t<<endl;
cout<<a[t]<<endl;
for(int i = 0; i <= 7; i++){
cout<<a[i]<<endl;
}
return 0;
}
- 关于lower_bound()函数的使用,这是一个高效的方法用二分查找数组中第一次出现某个数的引用,它接收三个参数,数组首地址,数组尾地址,需要查询的数的值,一般我们将查询出的结果减去数组名,则得到一个数组中下标为i的位置是第一次出现查找的number的位置
i = lower_bound(a + 1, a + n + 1, number) - a;
- 离散化:因为数据量i,j很大,而最多有1000000对输入,显然最多有2000000个不同的数字,我们可以构建一个2000000大的数组存放这所有的输入的i,j(尽管它们本身可能大大超出2000000但放在这个数组里却没有任何问题)
本题代码
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int N = 1000005;
int p[N<<1];
int m[N<<1];
int x[N];
int y[N];
int type[N];
int n, cnt, num;
struct Node{ //结构体是用于存放那些不同的数对的i j的第一次在数组中出现的位置
int x, y;
}k[N<<1];
void merge(){ //合并重复元素,实际上是覆盖操作,数组长度未发生变化,temp存放最后一个有序位置的索引(因为-m-1)
sort(m + 1, m + num + 1);
int temp = unique(m + 1, m + num + 1) - m - 1;
for(int i = 1; i <= n; i++){
x[i] = lower_bound(m + 1, m + temp + 1, x[i]) - m; //lowerbound()前两个参数的闭区间和开区间
y[i] = lower_bound(m + 1, m + temp + 1, y[i]) - m; //执行完成后x[i]存放m数组中第一次出现x[i]的位置
}
}
int find(int x){
if(p[x] == x) return x;
else{
p[x] = find(p[x]);
}
return p[x];
// while(p[x] != x){
// x = p[x];
// }
// return x;
}
void Union(int x, int y){
int fx = find(x);
int fy = find(y);
if(fx != fy) p[fy] = fx;
}
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
cnt = 0;
num = 0;
for(int i = 1; i <= n; i++){ //对输入的n组输入进行2*n的离散化处理
scanf("%d%d%d", &x[i], &y[i], &type[i]);
m[++num] = x[i];
m[++num] = y[i];
}
for(int i = 1; i <= num; i++) p[i] = i; //p数组存放根
merge();
for(int i = 1; i <= n; i++){
if(type[i] == 1){
Union(x[i], y[i]); //type == 1时 将根合并同时路径压缩,这里要注意,x[i] y[i]
}else{ //存放的是第一次出现位置,只有这样才能在2000000空间中查询1000000000大的数
k[++cnt].x = x[i]; //k结构体数组存放type == 0时数对x[i],y[i]第一次在数组m中出现的位置
k[cnt].y = y[i];
}
}
int flag = 0;
for(int i = 1; i <= cnt; i++){
int fx = find(k[i].x);
int fy = find(k[i].y);
if(fx == fy){ //如果根相同 则说明相等 矛盾
flag = 1;
printf("NO\n");
break;
}
}
if(flag == 0){
printf("YES\n");
}
}
return 0;
}
【NOI 2015】程序自动分析 并查集与离散化处理的更多相关文章
- 洛谷P1955 [NOI2015] 程序自动分析 [并查集,离散化]
题目传送门 题目描述 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3...代表程序中出现的变量,给定n个形如xi=xj或x ...
- BZOJ-4195 NOI2015Day1T1 程序自动分析 并查集+离散化
总的来说,这道题水的有点莫名奇妙,不过还好一次轻松A 4195: [Noi2015]程序自动分析 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 836 ...
- [BZOJ4195] [NOI2015] 程序自动分析 (并查集)
Description 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3,…代表程序中出现的变量,给定n个形如xi=xj或x ...
- BZOJ 4195: [Noi2015]程序自动分析 并查集+离散化
LUOGU 1955BZOJ 4195 题目描述 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3...代表程序中出现的变量 ...
- 【BZOJ4195】[Noi2015]程序自动分析 并查集
[BZOJ4195][Noi2015]程序自动分析 Description 在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3 ...
- BZOJ 4195: [Noi2015]程序自动分析 [并查集 离散化 | 种类并查集WA]
题意: 给出若干相等和不等关系,判断是否可行 woc NOI考这么傻逼的题飞快打了一个种类并查集交上了然后爆零... 发现相等和不等看错了异或一下再叫woc90分 然后发现md$a \neq b, a ...
- NOI2015程序自动分析 并查集
有10^9个点,每次给出两个点的关系:权相等或不等,问最后能不能成立 感觉一开始在撕烤一个动态的问题,,,想写一个带权的并查集 结果发现静态询问,那就sb乱搞,懒得手写离散就直接map(卧槽好多细节忘 ...
- bzoj4195 [Noi2015]程序自动分析——并查集
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4195 突然在这道大水题上WA了半天... 思路很简单,离线处理询问,先把 = 的都加到并查集 ...
- [Bzoj4195] [NOI2015] 程序自动分析 [并查集,哈希,map] 题解
用并查集+离散化,注意:并查集数组大小不是n而是n*2 #include <iostream> #include <algorithm> #include <cstdio ...
随机推荐
- 【JVM】02垃圾回收机制
垃圾回收 垃圾回收策略https://blog.csdn.net/u010425776/article/details/51189318 程序计数器.Java虚拟机栈.本地方法栈都是线程私有的,也就是 ...
- MAC iterm2 常用快捷键大全
标签 新建标签:command + t 关闭标签:command + w 切换标签:command + 数字 / command + 左右方向键 切换全屏:command + enter 查找:com ...
- Analysis of requirement specification of parking management system
Analysis of requirement specification of parking management system PURPOSE OF THE SYSTEM The parking ...
- 并发编程-concurrent指南-回环栅栏CyclicBarrier
字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行. java.util.concurrent.CyclicBarrier 类是一种同步机制,它能够对处理一些算法的线程实现同步 ...
- Python之Pandas库学习(三):数据处理
1. 合并 可以将其理解为SQL中的JOIN操作,使用一个或多个键把多行数据结合在一起. 1.1. 简单合并 参数on表示合并依据的列,参数how表示用什么方式操作(默认是内连接). >> ...
- Tomcat配置解析
Tomcat文件配置 tomcat解压后目录 bin:可执行文件(startup.bat shutdown.bat) conf:配置文件(server.xml) lib:tomcat依赖的jar文件 ...
- 扒一扒那些教程中不常被提及的JavaScript小技巧
1.过滤唯一值 Set类型是在ES6中新增的,它类似于数组,但是成员的值都是唯一的,没有重复的值.结合扩展运算符(...)我们可以创建一个新的数组,达到过滤原数组重复值的功能. const array ...
- Hash的应用
思路:此题比较简单,直接贴代码 #include <stdio.h> int main(){ int N; ){ ]={}; ;i<N;i++){ int x; scanf(&quo ...
- 和朱晔一起复习Java并发(二):队列
和朱晔一起复习Java并发(二):队列 老样子,我们还是从一些例子开始慢慢熟悉各种并发队列.以看小说看故事的心态来学习不会显得那么枯燥而且更容易记忆深刻. 阻塞队列的等待? 阻塞队列最适合做的事情就是 ...
- Flutter学习笔记(8)--Dart面向对象
如需转载,请注明出处:Flutter学习笔记(7)--Dart异常处理 Dart作为高级语言,支持面向对象的很多特性,并且支持基于mixin的继承方式,基于mixin的继承方式是指:一个类可以继承自多 ...