Codeforces1817-D. Subarray Sorting(关于排序的结论)

本文解析了CodeForces竞赛中一道关于数组排序操作的难题,通过贪心算法结合线段树实现对数组的高效检查与更新,确保目标数组可通过源数组的部分区间排序操作获得。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面:https://codeforc.es/contest/1187/problem/D
给出a、b两个数组,问对a进行部分区间排序操作(可无限次进行),能否得到b数组。

这题被hack炸了,愣是搞出173个测试样例。题解给出了一个有趣的结论:一个数可以往前移动的个数是前面所有数都比他大的区间有多长。

有了这个结论之后我们就可以对b数组每次都贪心的取a数组最左边的ai = bj的位置,然后检查ai能否被移动到开头(使用线段树来检查),如果可以,就把它移动到开头。

ac代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
//查询最左边的,与当前元素相等的
//还要判断区间最值

int _, n, a[maxn], b[maxn];

int t[maxn << 2];
queue<int> q[maxn];

void pushUp(int i) {
    t[i] = min(t[i << 1], t[i << 1 | 1]);
}

void build(int i, int l, int r) {
    if (l == r) {
        t[i] = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(i << 1, l, mid);
    build(i << 1 | 1, mid + 1, r);
    pushUp(i);
}

void update(int i, int l, int r, int pos, int val) {
    if (l == r) {
        t[i] = val;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) {
        update(i << 1, l, mid, pos, val);
    } else {
        update(i << 1 | 1, mid + 1, r, pos, val);
    }
    pushUp(i);
}

int query(int i, int l, int r, int L, int R) {
    if (l >= L && r <= R) {
        return t[i];
    }
    int mid = (l + r) >> 1;
    int ans = maxn;
    if (L <= mid) {
        ans = min(ans, query(i << 1, l, mid, L, R));
    }
    if (R > mid) {
        ans = min(ans, query(i << 1 | 1, mid + 1, r, L, R));
    }
    return ans;
}

int main() {
    ios::sync_with_stdio(0);
    cin >> _;
    while (_--) {
        cin >> n;
        for (int i = 1; i <= n; ++i) {
            while (!q[i].empty()) {
                q[i].pop();
            }
        }
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
            q[a[i]].push(i);
        }
        build(1, 1, n);
        for (int i = 1; i <= n; ++i) {
            cin >> b[i];
        }

        bool flag = 1;
        for (int i = 1; flag && i <= n; ++i) {
            if (q[b[i]].empty()) {
                flag = 0;
                break;
            }

            int minn = query(1, 1, n, 1, q[b[i]].front());
            if (minn < b[i]) {
                flag = 0;
                break;
            }
            update(1, 1, n, q[b[i]].front(), maxn);
            q[b[i]].pop();
        }

        if (flag) {
            cout << "YES\n";
        } else {
            cout << "NO\n";
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值