Codeforces Round #668 2E 1C

题解

为了方便计算, 我们将原数组, 全部替换为 a[i] = i - a[i]

对于 a[i] = 0 的是直接可以删除的, a[i] < 0 是不能删除的, 可以变为 a[i] = n + 1(不可能删除)

每个询问 x, y 针对的区间是 [x + 1, n - y], l = x + 1, r = n - y

因为是,从左向右, 我们考虑枚举 r

假设我们知道了 F[1, r - 1] 的答案, 那么 F[1, r] = F[1, r - 1] + (a[i] <= F[1, r - 1])

假设我们知道了 F[l, r - 1] 的答案, 那么 F[l, r] = F[l, r - 1] + (a[i] <= F[l, r - 1])

问题就是如何求 F[l, l] 即 a[l] 对 [1~l, l~n] 的贡献

由于是枚举r, 可以简化 F[l, r] 为 当前 r 下 F[l]

对于 1 < l < r, 我们在 r = r - 1的时候 F[l] 已经知道了

我们只要计算 F[r] 对 F[1 ~ r - 1] 的影响就行了

即 找到最大的 l_max, 使得 F[l_max] == a[r], 那么 F[1 ~ l_max] ++, 所有都使得 a[i] 变成0 (在 r 固定的前提下)

ps: 为什么找最大? 是l_max, 使得 F[1 ~ l_max - 1]++ 的, 本质是 l_max 做出最后的贡献, 使得 a[i] 变成 0

这样 原本 for (r, 1, n) for (l, 1, r) 的 O(n^2) 就变成了

for (r, 1, n) find(l_max) 想办法优化 find(l_max) 这一步

在找到 l_max 设计了区间操作, 那么就有了线段树, 树状数组等数据结构, 增删改查上限 都是 O(logn) 复杂度就够了

找 l_max 用二分

最后按照 r = n - y 的顺序 离线 回答问题即可

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;

const int N = 3e5 + 5;

int n, m, _, k;
int c[N], a[N], ans[N];
vector<PII> q[N];

void add(int x, int k) {
    for (; x <= n; x += -x & x) c[x] += k;
}

int ask(int x) {
    int ans = 0;
    for (; x; x -= x & -x) ans += c[x];
    return ans;
}

int main() {
    IOS; cin >> n >> m;
    rep (i, 1, n) cin >> k, a[i] = i - k < 0 ? n + 1 : i - k;
    rep (i, 1, m) {
        int x, y; cin >> x >> y;
        q[n - y].pb({ x + 1, i });
    }

    rep (i, 1, n) {
        int l = 0, r = i;
        while (l < r) {
            int mid = (l + r + 1) >> 1;
            if (ask(mid) >= a[i]) l = mid;
            else r = mid - 1;
        }
        add(1, 1); add(l + 1, -1);
        for (auto &[x, idx] : q[i]) ans[idx] = ask(x);
    }

    rep (i, 1, m) cout << ans[i] << '\n';
    return 0;
}
posted @ 2020-09-07 13:29  洛绫璃  阅读(130)  评论(0编辑  收藏  举报