[Codeforces 992E] Nastya and King-Shamans

https://codeforces.com/contest/992/problem/E

题意:
给定序列,每次单点修改后,求是否有点 \(p\) 的权值等于 \(1\) ~ \(p - 1\) 的权值和。

思路:
设前缀和数组为 \(pre\) ,考虑将单点权值改为 \(a_i - pre[i - 1]\) ,然后只需要每次修改时维护一下,最后数个 \(0\) 。注意到若权值为正数,对前缀和的影响是一个斐波那契数列,所以修改后的权值 \(a'\) 中,正数的数量很少。利用这一性质,我们在线段树上二分即可。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 7;

ll a[N], preSum[N];

struct Seg {
#define ls (id << 1)
#define rs (id << 1 | 1)
#define mid ((l + r) >> 1)
    ll mx[N << 2], lz[N << 2];

    void up(int id) {
        mx[id] = max(mx[ls], mx[rs]);
    }

    void down(int id) {
        if (!lz[id]) return;
        lz[ls] += lz[id];
        lz[rs] += lz[id];
        mx[ls] += lz[id];
        mx[rs] += lz[id];
        lz[id] = 0;
        return;
    }

    void build(int id, int l, int r) {
        if (l == r) {
            mx[id] = a[l] - preSum[l - 1];
            return;
        }
        build(ls, l, mid);
        build(rs, mid + 1, r);
        up(id);
    }

    void modify(int id, int l, int r, int ql, int qr, ll v) {
        if (l > qr || r < ql) return;
        if (l >= ql && r <= qr) {
            mx[id] += v;
            lz[id] += v;
            return;
        }
        down(id);
        modify(ls, l, mid, ql, qr, v);
        modify(rs, mid + 1, r, ql, qr , v);
        up(id);
    }

    int query(int id, int l, int r) {
        if (mx[id] < 0) return -1;
        if (l == r) {
            if (mx[id] == 0) return l;
            else return -1;
        }
        down(id);
        int pos = query(ls, l, mid);
        if (pos == -1) pos = query(rs, mid + 1, r);
        return pos;
    }
}seg;

int n, m;

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        preSum[i] = a[i] + preSum[i - 1];
    }
    seg.build(1, 1, n);
    int pos, v;
    while (m--) {
        cin >> pos >> v;
        ll add = v - a[pos];
        seg.modify(1, 1, n, pos, pos, add);
        seg.modify(1, 1, n, pos + 1, n, -add);
        a[pos] = v;
        cout << seg.query(1, 1, n) << '\n';
    }
}

int main() {
#ifndef stff577
    ios::sync_with_stdio(false);
    cin.tie(nullptr);cout.tie(nullptr);
    cout << fixed << setprecision(20);
#endif
    int t = 1;
    while (t--) solve();
    return 0;
}
posted @ 2022-08-09 16:18  stff577  阅读(26)  评论(0编辑  收藏  举报