CF 1023D Array Restoration - 线段树

题解

非常容易想到的线段树, 还可以用并查集来。 还有一位大神用了$O(n)$ 就过了Orz

要判断是否能染色出输入给出的序列,必须满足两个条件:

1、 序列中必须存在一个$q$

2、 两个相同的数$x$的中间不存在比 $ x$ 小的数

首先判断输入的数列中是否存在$q$, 若不存在$q$ 且没有 $a_i = 0$, 表示序列中一定没有$q$, 直接输出NO

  若存在某个$a_i = 0$ , 将任意一个染成p即可

然后我们再查询两个相同的数$x$ 中是否存在比$x$ 小的数,用线段树来维护区间最小即可实现

  接着把两个$x$中间的序列染色, 用MinOK来记录,表示区间内$a_i = 0$,可以染色的最小值。 (线段树区间修改

  最后把$a_i = 0$ 进行染色(利用线段树点查询

CF现场就想到的算法,然而没有特判存在$q$,pushdown还少打了唔, CF百分百掉分,我要变成pupil了,太惨啦QAQ

代码

  1 #include<cstring>
  2 #include<algorithm>
  3 #include<cstdio>
  4 #define lson nd<<1
  5 #define rson nd<<1|1
  6 #define rd read()
  7 #define rep(i,a,b) for(int i = (a); i <= (b); ++i)
  8 #define per(i,a,b) for(int i = (a); i >= (b); --i)
  9 using namespace std;
 10 
 11 const int N = 3e5, inf = ~0U >> 2;
 12 
 13 int MIN[N << 2], a[N], L[N], R[N], lazy[N << 2], q, n, pos;
 14 int Mok[N << 2];
 15 
 16 int read() {
 17     int X = 0, p = 1; char c = getchar();
 18     for(; c > '9' || c < '0'; c = getchar()) if( c == '-') p = -1;
 19     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
 20     return X * p;
 21 }
 22 
 23 void update(int nd) {
 24     MIN[nd] = min(MIN[lson], MIN[rson]);
 25 }
 26 
 27 void pushdown(int nd) {
 28     if(lazy[nd]) {
 29         Mok[lson] = lazy[nd];
 30         Mok[rson] = lazy[nd];
 31         lazy[lson] = lazy[rson] = lazy[nd];
 32         lazy[nd] = 0;
 33     }
 34 }
 35 
 36 void build(int l, int r, int nd) {
 37     if(l == r) {
 38         MIN[nd] = a[l] == 0 ? inf : a[l];
 39         return;
 40     }
 41     int mid = (l + r) >> 1;
 42     build(l, mid, lson);
 43     build(mid + 1, r, rson);
 44     update(nd);
 45 }
 46 
 47 int query(int Li, int Ri, int l, int r, int nd) {//查询区间最小
 48     if(Li <= l && r <= Ri) return MIN[nd];
 49     int mid = (l + r) >> 1, re = inf;
 50     if(Li <= mid) re = min(re, query(Li, Ri, l, mid, lson));
 51     if(mid < Ri) re = min(re, query(Li, Ri, mid + 1, r, rson));
 52     return re;
 53 }
 54 
 55 int query_pt(int p, int l, int r, int nd) {//查询可以染上的值
 56     if(l == r) return Mok[nd];
 57     int mid = (l + r) >> 1;
 58     pushdown(nd);
 59     if(p <= mid) return query_pt(p, l, mid, lson);
 60     else return query_pt(p, mid + 1, r, rson);
 61 }
 62 
 63 void change(int Li, int Ri, int c, int l, int r, int nd) {
 64     if(Li <= l && r <= Ri) {
 65         lazy[nd] = c;
 66         Mok[nd] = c;
 67         return;
 68     }
 69     int mid = (l + r) >> 1;
 70     pushdown(nd);
 71     if(Li <= mid) change(Li, Ri, c, l, mid, lson);
 72     if(mid < Ri) change(Li, Ri, c, mid + 1, r, rson);
 73     update(nd);    
 74 }
 75 
 76 int main()
 77 {
 78     n = rd; q = rd;
 79     for(int i = 1; i <= n; ++i) {
 80         a[i] = rd;
 81         if(!a[i]) pos = i;
 82         if(!L[a[i]]) L[a[i]] = i;
 83         R[a[i]] = i;
 84     }
 85     if(!L[q] && !pos) return printf("NO\n"), 0;//无a[i]=0也无q
 86     build(1, n, 1);
 87     for(int i = 1; i <= q; ++i) {//必须按颜色从小到大覆盖
 88         if(!L[i]) continue;
 89         int minv = query(L[i], R[i], 1, n, 1);
 90         if(minv < i) return printf("NO\n"), 0;
 91         change(L[i], R[i], i, 1, n, 1);
 92     }
 93     for(int i = 1; i <= n; ++i) if(!a[i]) {
 94         a[i] = query_pt(i, 1, n, 1);
 95         if(i == pos && !L[q]) a[i] = q; // 必须存在q
 96         else if(!a[i]) a[i] = 1;
 97     }
 98     printf("YES\n");
 99     for(int i = 1; i <= n; ++i) printf("%d ", a[i]);
100     putchar('\n');
101 }
View Code

 

猜你喜欢

转载自www.cnblogs.com/cychester/p/9502367.html