codeforces 1023 D. Array Restoration 并查集
1 second
256 megabytes
standard input
standard output
Initially there was an array $$$a$$$ consisting of $$$n$$$ integers. Positions in it are numbered from $$$1$$$ to $$$n$$$.
Exactly $$$q$$$ queries were performed on the array. During the $$$i$$$-th query some segment $$$(l_i, r_i)$$$ $$$(1 \le l_i \le r_i \le n)$$$ was selected and values of elements on positions from $$$l_i$$$ to $$$r_i$$$ inclusive got changed to $$$i$$$. The order of the queries couldn't be changed and all $$$q$$$ queries were applied. It is also known that every position from $$$1$$$ to $$$n$$$ got covered by at least one segment.
We could have offered you the problem about checking if some given array (consisting of $$$n$$$ integers with values from $$$1$$$ to $$$q$$$) can be obtained by the aforementioned queries. However, we decided that it will come too easy for you.
So the enhancement we introduced to it is the following. Some set of positions (possibly empty) in this array is selected and values of elements on these positions are set to $$$0$$$.
Your task is to check if this array can be obtained by the aforementioned queries. Also if it can be obtained then restore this array.
If there are multiple possible arrays then print any of them.
The first line contains two integers $$$n$$$ and $$$q$$$ ($$$1 \le n, q \le 2 \cdot 10^5$$$) — the number of elements of the array and the number of queries perfomed on it.
The second line contains $$$n$$$ integer numbers $$$a_1, a_2, \dots, a_n$$$ ($$$0 \le a_i \le q$$$) — the resulting array. If element at some position $$$j$$$ is equal to $$$0$$$ then the value of element at this position can be any integer from $$$1$$$ to $$$q$$$.
Print "YES" if the array $$$a$$$ can be obtained by performing $$$q$$$ queries. Segments $$$(l_i, r_i)$$$ $$$(1 \le l_i \le r_i \le n)$$$ are chosen separately for each query. Every position from $$$1$$$ to $$$n$$$ should be covered by at least one segment.
Otherwise print "NO".
If some array can be obtained then print $$$n$$$ integers on the second line — the $$$i$$$-th number should be equal to the $$$i$$$-th element of the resulting array and should have value from $$$1$$$ to $$$q$$$. This array should be obtainable by performing exactly $$$q$$$ queries.
If there are multiple possible arrays then print any of them.
4 3
1 0 2 3
YES
1 2 2 3
3 10
10 10 10
YES
10 10 10
5 6
6 5 6 2 2
NO
3 5
0 0 0
YES
5 4 2
In the first example you can also replace $$$0$$$ with $$$1$$$ but not with $$$3$$$.
In the second example it doesn't really matter what segments to choose until query $$$10$$$ when the segment is $$$(1, 3)$$$.
The third example showcases the fact that the order of queries can't be changed, you can't firstly set $$$(1, 3)$$$ to $$$6$$$ and after that change $$$(2, 2)$$$ to $$$5$$$. The segment of $$$5$$$ should be applied before segment of $$$6$$$.
There is a lot of correct resulting arrays for the fourth example.
最后一次操作一定不会被覆盖,第q次操作后只能有一个[q],只有两种合法的情况:
只有一个[q];有若干个[q],且[q]之间必须全部是[0]。
对第q-1次操作的检查也是同理,因为q-1只可能被[q]覆盖,两个[q-1]之间只能出现[0]或[q],只有下面两种合法的情况:
只有一个[q-1];有若干个[q-1],且必须是[q-1][0][q-1]或[q-1][q][q-1]的形式。
为了方便检查两个[q-1]之间是否为[q]或[0],在上一步处理[q]的时候,可以把[q]之间的[0]全部变为[q],最后让q变成连通的一整块,这样就只用检查是否为[q]了。
对第q-2次操作的检查就是:
只有一个[q-2];有若干个[q-2],且两两之间必须全部是[q-2][0][q-2], [q-2][q-1][q-2], [q-2][q][q-2], [q-2][q][q-1][q-2],[q-2][q-1][q][q-1][q-2],...。
注意到合法的情况将越来越多,但其实只需要检查[q-2][x]...[y][q-2]中,与[q-2]直接相邻的两个[x][y]就可以了。如果[x]...[y]中没有[0],那么[x]...[y]全为[q]或[q-1]的充分必要条件,就是[x],[y]都为[q]或[q-1],如果存在反例,那么q-1的检查一定不能通过。
为了方便检查,我们不希望在[x]...[y]有[0]的存在,可以在检查[q-1]的之前,把与[q-1]相邻的[0]全部设为[q-1],在检查[q-2]之前,把[q-2]相邻的[0]全部设为[q-2]。
依次类推,对第i次操作的检查,首先把所有[i]相邻的[0]设为[i],再检查[i][x]..[y][i]的内部,[x]...[y]则一定都是不小于[x], [y]的数,那么合法的充分必要条件就是[x]和[y]都比i大。
这样处理到最后,发现所有的[0]都被填充了,所以直接按[i]整段输出就可以了。
#include<stdio.h> #define N_max 200005
int n,q;
int ipt[N_max],now[N_max];
int lg[N_max],rg[N_max];//并查集的范围
int fst[N_max],nxt[N_max];//并查集的链表 //#define debug there_is_no_bug_at_all_if_you_cannot_see_these_words_:( int main(){
scanf("%d %d",&n,&q);
int last,fr;
scanf("%d",ipt+);
last=ipt[];fr=;lg[]=;
for(int i=;i<=n;++i){
scanf("%d",ipt+i);
if(ipt[i]!=last){//出现新的值
/*将i-1代表的并查集插入链表*/
nxt[i-]=fst[last];
fst[last]=i-;
/*在头部记录并查集覆盖的范围,以及值*/
lg[i-]=fr;rg[i-]=i-;now[i-]=last;
//在并查集的尾部也要记录整个并查集范围
rg[fr]=i-;
/*准备下一个并查集*/
fr=i;last=ipt[i];lg[fr]=fr;
}
}
//把最后一段并查集也添加进来
nxt[n]=fst[last];
fst[last]=n;
lg[n]=fr;rg[n]=n;now[n]=last;
rg[fr]=n; //值为q的并查集至少有一个,如果没有就把一个0设为q
if(fst[q]==){
if(fst[]==){//没有0则是不合法的
printf("NO");return ;
}
now[fst[]]=q;
fst[q]=fst[];
fst[]=nxt[fst[]];nxt[fst[q]]=;
}
int ln;
for(int t=q;t>=;--t){//扫描所有值为t的并查集 if(now[rg[fst[t]+]]==)/*因为是从右向左遍历的,如果第一个t右边的并查集是0,则将他设为t*/
now[rg[fst[t]+]]=t;
for(ln=fst[t];ln;ln=nxt[ln])if(now[lg[ln]-]==)/*所有t左边的并查集如果是0则设为t*/
now[lg[ln]-]=t;
for(ln=nxt[fst[t]];ln;ln=nxt[ln])/*再次遍历,检查并查集之间是否出现了更小的值*/
if(now[rg[ln+]]<t){printf("NO");return ;}
}
printf("YES\n");
for(int i=;i<=n;){//输出的时候按并查集输出
for(int t=i;t<=rg[i];++t)
printf("%d ",now[rg[i]]);
i=rg[i]+;
}
}
codeforces 1023 D. Array Restoration 并查集的更多相关文章
- CodeForces - 722C Destroying Array (并查集/集合的插入和删除)
原题链接:https://vjudge.net/problem/511814/origin Description: You are given an array consisting of n no ...
- Codeforces 699D Fix a Tree 并查集
原题:http://codeforces.com/contest/699/problem/D 题目中所描述的从属关系,可以看作是一个一个块,可以用并查集来维护这个森林.这些从属关系中会有两种环,第一种 ...
- Codeforces 731C:Socks(并查集)
http://codeforces.com/problemset/problem/731/C 题意:有n只袜子,m天,k个颜色,每个袜子有一个颜色,再给出m天,每天有两只袜子,每只袜子可能不同颜色,问 ...
- codeforces 400D Dima and Bacteria 并查集+floyd
题目链接:http://codeforces.com/problemset/problem/400/D 题目大意: 给定n个集合,m步操作,k个种类的细菌, 第二行给出k个数表示连续的xi个数属于i集 ...
- Codeforces 1027F Session in BSU - 并查集
题目传送门 传送门I 传送门II 传送门III 题目大意 有$n$门科目有考试,第$i$门科目有两场考试,时间分别在$a_i, b_i\ \ (a_i < b_i)$,要求每门科目至少参加 ...
- CodeForces - 455C Civilization (dfs+并查集)
http://codeforces.com/problemset/problem/455/C 题意 n个结点的森林,初始有m条边,现在有两种操作,1.查询x所在联通块的最长路径并输出:2.将结点x和y ...
- Codeforces 859E Desk Disorder:并查集【两个属性二选一】
题目链接:http://codeforces.com/problemset/problem/859/E 题意: 有n个人,2n个座位. 给出这n个人初始的座位,和他们想坐的座位. 每个人要么坐在原来的 ...
- Codeforces 651E Table Compression【并查集】
题目链接: http://codeforces.com/problemset/problem/650/C 题意: 给定n*m的矩阵,要求用最小的数表示每个元素,其中各行各列的大小关系保持不变. 分析: ...
- codeforces 456 E. Civilization(并查集+数的直径)
题目链接:http://codeforces.com/contest/456/problem/E 题意:给出N个点,M条边,组成无环图(树),给出Q个操作,操作有两种: 1 x,输出x所在的联通块的最 ...
随机推荐
- 20155231 信息安全技术概论实验二 Windows口令破解
20155231 信息安全技术概论实验二 Windows口令破解 实验目的 了解Windows口令破解原理 对信息安全有直观感性认识 能够运用工具实现口令破解 实验人数 每组一人 系统环境 windo ...
- 20155305乔磊2016-2017-2《Java程序设计》第三周学习总结
20155305乔磊 2016-2017-2 <Java程序设计>第三周学习总结 教材学习内容总结 对象(Object):存在的具体实体,具有明确的状态和行为 类(Class):具有相同属 ...
- P,NP,NPC的通俗解释
这或许是众多OIer最大的误区之一. 你会经常看到网上出现“这怎么做,这不是NP问题吗”.“这个只有搜了,这已经被证明是NP问题 了”之类的话.你要知道,大多数人此时所说的NP问题其实都是指的N ...
- 微服务(SOP)日志管理
问题: 大型企业应用规模大,调试 / 解决问题由于在生产环境中不会有开发环境的调试工具,如果需要模拟还原当时的环境, 目前的解决办法是进行日志记录 日志记录的常用方式: 使用SpringAop进行切入 ...
- [agc010D]Decrementing-[。。。思考题]
Description 传送门 Solution 真是够神秘的啊... Alice和Bob两个真的城会玩. 不过本题一个暗示挺明显的.就是黑板上所有数不论何时gcd为1. 考场上我以为会很复杂,结果. ...
- 从原理到代码:大牛教你如何用 TensorFlow 亲手搭建一套图像识别模块 | AI 研习社
从原理到代码:大牛教你如何用 TensorFlow 亲手搭建一套图像识别模块 | AI 研习社 PPT链接: https://pan.baidu.com/s/1i5Jrr1N 视频链接: https: ...
- 【转载】GC基本算法及C++GC机制
原文: GC基本算法及C++GC机制 阅读目录 前言 基本概念 有向可达图与根集 三种基本的垃圾收集算法及其改进算法 1.引用计数算法 2. Mark & Sweep 算法 3. 节点复制算法 ...
- day1 Opencv安装 python 2.7 (32位)
[参考安装步骤] http://opencv-python-tutroals.readthedocs.io/en/latest/index.html http://blog.csdn.net/huru ...
- IAR里面STM32工程使用printf
1. 首先打开工程的options设置 2. 设置编译器的预宏定义,添加宏定义_DLIB_FILE_DESCRIPTOR 3. 修改文件DLib_Defaults.h DLib_Defaults.h ...
- 使用T4模板报错:“正在编译转换;当前上下文中不存在名称Host”
用T4模板生成多个文件的实体时,有一句代码是这样的 string curPath = Path.GetDirectoryName(Host.TemplateFile); ...