zoukankan      html  css  js  c++  java
  • 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] << '
    ';
        return 0;
    }
    
  • 相关阅读:
    真的要努力了
    实事求是
    要努力了
    新征程,新目标
    真的要放弃了吗
    集中力量 主攻文科
    May the force be with me.
    记录级排名
    Android开发过程中git、repo、adb、grep等指令的使用
    Ubuntu环境变量设置
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/13626341.html
Copyright © 2011-2022 走看看