codeforces 1023 D Array Restoration (树状数组)

题面

在这里插入图片描述

题意

有一个长度为n的序列,你可以进行 q 次修改,第i次修改将区间 [l,r] 的数修改成 i ,涉及的 q次修改必须要覆盖区间中的每个数,q 次修改之后,将这个序列中的某些数变为0,得到一个新的序列(就是输入的序列),问你能不能通过这个新的序列求出一个变0之前的合法序列

题解

  1. 要求的这个字符串肯定是要有q的,因为q是最后一次修改,修改之后肯定有q,那么就要求输入的这个序列要么包含q,要么包含0(我们就可以将0变为q),如果输入的序列既没有q也没0,那么一定输出NO
  1. 要想有合法序列,那么就要保证输入的序列也合法,对于输入的序列,因为每次修改都是修改一段区间,而且修改之后肯定是变大的,所以两个相同数字区间是不可能出现比它小的数字的,,例如 6 5 6 肯定是不合法的,对于第6次修改,我们只能将一段区间的数修改为6且只有这一次机会,所以要修改只能是把5也一起修改,就不可能出现上述情况
  1. 知道这个性质,我们就可以用树状数组巧妙的判断是否为合法序列,对于第一次出现的数,我们可以标记一下比它小的数有多少,当第二次遇到这个数时,我们只要判断比它小的数是否多了,如果是多了,那么在这区间一定是有小于这个数的数了,设计的操纵不就是在一个位置添加1,然后查询前缀和(小于这个数的个数),妥妥的树状数组
  1. 对于输出,肯定是要连续的一段数字相同比较方便,所以对于0,我们直接让它等于前一个数即可,但是要注意,就是当输入的序列没有q时,我们要先将0转化为q(因为序列中必须出现一个q)

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 2e5 + 10;

int n, q;
int a[N], vis[N];
int tr[N];

int lowbit(int x) {
    return x & -x;
}

void add(int x, int c) {
    for (int i = x; i <= q; i += lowbit(i)) tr[i] += c;
}

int sum(int x) {
    int res = 0;
    for (int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

int main() {

    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    cin >> n >> q;
    for (int i = 1; i <= n; i++) cin >> a[i];

    bool flag = true;
    for (int i = 1; i <= n; i++) {
        if (a[i] == 0) continue;
        if (vis[a[i]]) {   //说明之前出现过
            if (vis[a[i]] != sum(a[i])) {  //说明中间出现过小于a[i]的数
                flag = false;
                break;
            }
        }
        add(a[i], 1);
        vis[a[i]] = sum(a[i]);
    }

    if (flag) {
        bool zero = false, isq = false;
        for (int i = 1; i <= n; i++) {
            if (a[i] == 0) zero = true;
            if (a[i] == q) isq = true;
        }
        if (!(zero || isq)) {
            cout << "NO" << endl;
        } else {
            a[0] = 1;
            for (int i = 1; i <= n; i++) {
                if (a[i] == 0) {
                    if (!isq) {
                        a[i] = q;
                        isq = true;
                    } else {
                        a[i] = a[i - 1];
                    }
                }
            }
            cout << "YES" << endl;
            for (int i = 1; i <= n; i++) {
                cout << a[i] << " ";
            }
            cout << endl;
        }
    } else {
        cout << "NO" << endl;
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值