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所在的联通块的最 ...
随机推荐
- java开发工具使用
一.MyEclipse软件的使用 1)ctrl+n新建文件 2)ctrl+d删除一行 3)alt+/提示补齐 (main/syso/syse/for遍历最近的数组) 4)ctrl+shift+f格式化 ...
- CF 1083 A. The Fair Nut and the Best Path
A. The Fair Nut and the Best Path https://codeforces.com/contest/1083/problem/A 题意: 在一棵树内找一条路径,使得从起点 ...
- 【转】 线段树完全版 ~by NotOnlySuccess
载自:NotOnlySuccess的博客 [完全版]线段树 很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章 ...
- 跨域发送HTTP请求详解
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客讲述几种跨域发HTTP请求的几种方法,POST请求,GET请求 目录: 一,采用JsonP的方式(只能 ...
- pyhon3.0 day01 变量、输入、输出、循环
pyhon3.0 基础01 1 python解释器 Python的解释器很多,但使用最广泛的还是CPython.如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython, ...
- pg执行计划
- POJ-3273(二分)
//题意:给出农夫在n天中每天的花费,要求把这n天分作m组, //每组的天数必然是连续的,要求分得各组的花费之和应该尽可能地小,最后输出各组花费之和中的最大值. //思路:看到各组最小和最大的,果断上 ...
- 《零基础学JavaScript(全彩版)》学习笔记
<零基础学JavaScript(全彩版)>学习笔记 二〇一九年二月九日星期六0时9分 前期: 刚刚学完<零基础学HTML5+CSS3(全彩版)>,准备开始学习JavaScrip ...
- NO.08--VUE之自定义组件添加原生事件
前几篇给大家分享了我的业余的“薅羊毛”的经历,回归正题,讲回vue吧: 许多vue新手在工作开发中会遇到一个问题,直接使用 button 添加原生事件是没有问题的,但是使用自定义组件添加原生事件时,就 ...
- thinkphp5框架生成二维码(二)
上篇已经讲过了SDK之类的,这个不再重复,有不知道的童鞋们,请去看上篇文章吧. 这里我用的方法比较老旧,大家有更好的方法,可以进行改良,还有linux服务器,记得给文件权限,否则生成的文件会失败的.大 ...