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所在的联通块的最 ...
随机推荐
- 20155332 2006-2007-2 《Java程序设计》第2周学习总结
20155332 2006-2007-2 <Java程序设计>第2周学习总结 教材学习内容总结 在JAVA中分为基本类型和类类型两大类型系统. JAVA中的基本类型主要分为如下几类: 1. ...
- logstash patterns github
USERNAME [a-zA-Z0-9._-]+ USER %{USERNAME} INT (?:[+-]?(?:[0-9]+)) BASE10NUM (?<![0-9.+-])(?>[+ ...
- linux Ubuntu Kali 安装flash
http://jingyan.baidu.com/article/fa4125accdeeec28ad709252.html
- css图片文字一排
<div class="footer1"> <div class="vercital-head"></div><!-- ...
- 海思NB-IOT HI2115芯片电压域的问题
1. 先看模块引脚,利尔达NB86-G模块 2. VDD_IO_R1, VDD_IO_R2, VDD_IO_L1 and VDD_IO_L2 control the IO voltages on PI ...
- LUIS 语义识别API调用方法
本例使用itchat获取微信文字消息,发送给LUIS返回识别消息,再将返回消息格式化后通过微信发回 关于itchat的使用参考我的另外一篇随笔itchat个人练习 语音与文本图灵测试例程 # -*- ...
- Linux权限管理命令
查询linux命令用法网址:cht.sh 1.chmod——改变文件/目录的权限 用法: ① chmod [{ugoa}{+-=}{rwx}] [文件/目录] ---给文件的(用户.所属组.其他人 ...
- 使用Photon引擎进行unity网络游戏开发(一)——Photon引擎简介
使用Photon引擎进行unity网络游戏开发(一)--Photon引擎简介 Photon PUN Unity 网络游戏开发 Photon引擎简介: 1. 服务器引擎: 服 务 器 引 擎 介 绍 服 ...
- Spring学习(3):Spring概述(转载)
1. Spring是什么? Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发. 在面向对象思想中 ...
- cinder的组件
跟nova相似,cinder也有很多组件,每个组件负责各自的业务,然后共同协作完成volume的管理.组件之间的通信方式与nova个组件之间的通信方式相同,都是通过消息队列进行通信. cinder-a ...