1. 程式人生 > 實用技巧 >#線段樹、樹狀陣列#D 籌備計劃

#線段樹、樹狀陣列#D 籌備計劃


分析

首先這個位置應該是帶權中位數\((\geq \frac{sum+1}{2}(奇數要加一,WA了幾次了))\),但是既然有這個選擇的限制,
那麼要用線段樹求出可選擇的前驅和後繼,然後用樹狀陣列計算貢獻,拆開計算就可以了


程式碼

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
typedef long long lll;
const int N = 200011;
lll a[N];
int n, m, two[21], w[N << 2], lazy[N << 2];
inline signed iut() {
    rr int ans = 0;
    rr char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
    return ans;
}
inline void print(int ans) {
    if (ans > 9)
        print(ans / 10);
    putchar(ans % 10 + 48);
}
inline signed fan(int x) { return n - x + 1; }
struct Tree_Array {
    lll c[N];
    inline void update(int x, lll y) {
        for (; x <= n; x += -x & x) c[x] += y;
    }
    inline lll query(int x) {
        rr lll ans = 0;
        for (; x; x -= -x & x) ans += c[x];
        return ans;
    }
} CF[2], CR[2];
inline void build(int k, int l, int r) {
    w[k] = r - l + 1, lazy[k] = -1;
    if (l == r)
        return;
    rr int mid = (l + r) >> 1;
    build(k << 1, l, mid);
    build(k << 1 | 1, mid + 1, r);
}
inline void pdown(int k, int l, int mid, int r) {
    w[k << 1] = lazy[k] * (mid - l + 1), w[k << 1 | 1] = lazy[k] * (r - mid);
    lazy[k << 1] = lazy[k << 1 | 1] = lazy[k], lazy[k] = -1;
}
inline void update(int k, int l, int r, int x, int y, int z) {
    if (l == x && r == y) {
        w[k] = z * (r - l + 1), lazy[k] = z;
        return;
    }
    rr int mid = (l + r) >> 1;
    if (~lazy[k])
        pdown(k, l, mid, r);
    if (y <= mid)
        update(k << 1, l, mid, x, y, z);
    else if (x > mid)
        update(k << 1 | 1, mid + 1, r, x, y, z);
    else
        update(k << 1, l, mid, x, mid, z), update(k << 1 | 1, mid + 1, r, mid + 1, y, z);
    w[k] = w[k << 1] + w[k << 1 | 1];
}
inline signed sum_pre(int k, int l, int r, int x, int y) {
    if (l == x && r == y)
        return w[k];
    rr int mid = (l + r) >> 1;
    if (~lazy[k])
        pdown(k, l, mid, r);
    if (y <= mid)
        return sum_pre(k << 1, l, mid, x, y);
    else if (x > mid)
        return sum_pre(k << 1 | 1, mid + 1, r, x, y);
    else
        return sum_pre(k << 1, l, mid, x, mid) + sum_pre(k << 1 | 1, mid + 1, r, mid + 1, y);
}
inline signed query(int k, int l, int r, int kth) {
    if (l == r)
        return l;
    rr int mid = (l + r) >> 1;
    if (~lazy[k])
        pdown(k, l, mid, r);
    if (kth <= w[k << 1])
        return query(k << 1, l, mid, kth);
    else
        return query(k << 1 | 1, mid + 1, r, kth - w[k << 1]);
}
inline lll calc(int now) {
    rr lll ans = 0;
    if (now > 1)
        ans += CF[1].query(now - 1) - CF[0].query(now - 1) * (n - now);
    if (now < n)
        ans += CR[1].query(fan(now + 1)) - CR[0].query(fan(now + 1)) * (now - 1);
    return ans;
}
signed main() {
    freopen("position.in", "r", stdin);
    freopen("position.out", "w", stdout);
    n = iut(), m = iut(), build(1, 1, n), two[0] = 1;
    for (rr int i = 1; i < 21; ++i) two[i] = two[i - 1] << 1;
    for (rr int i = 1; i <= n; ++i) a[i] = iut();
    for (rr int i = 1; i <= n; ++i) CF[0].c[i] = CF[0].c[i - 1] + a[i];
    for (rr int i = 1; i <= n; ++i) CF[1].c[i] = CF[1].c[i - 1] + a[i] * (n - i);
    for (rr int i = 1; i <= n; ++i) CR[0].c[i] = CR[0].c[i - 1] + a[n - i + 1];
    for (rr int i = 1; i <= n; ++i) CR[1].c[i] = CR[1].c[i - 1] + a[n - i + 1] * (n - i);
    for (rr int i = n; i; --i) CF[0].c[i] -= CF[0].c[i & (i - 1)];
    for (rr int i = n; i; --i) CF[1].c[i] -= CF[1].c[i & (i - 1)];
    for (rr int i = n; i; --i) CR[0].c[i] -= CR[0].c[i & (i - 1)];
    for (rr int i = n; i; --i) CR[1].c[i] -= CR[1].c[i & (i - 1)];
    for (rr int z, x, y; m; --m, putchar(10)) {
        z = iut(), x = iut(), y = iut();
        if (z == 1 || z == 2) {
            y = (z == 1) ? y : -y, a[x] += y;
            CF[0].update(x, y);
            CF[1].update(x, 1ll * y * (n - x));
            CR[0].update(fan(x), y);
            CR[1].update(fan(x), 1ll * y * (x - 1));
        } else
            update(1, 1, n, x, y, 4 - z);
        if (!w[1]) {
            printf("-1");
            continue;
        }
        rr lll t = (CF[0].query(n) + 1) >> 1, sum = 0, ans = 0;
        for (rr int I = 17; ~I; --I)
            if (ans + two[I] <= n && sum + CF[0].c[ans + two[I]] < t)
                ans += two[I], sum += CF[0].c[ans];
        rr int t1 = -1, t2 = -1, s = sum_pre(1, 1, n, 1, ++ans);
        if (s > 0)
            t1 = query(1, 1, n, s);
        if (s < w[1])
            t2 = query(1, 1, n, s + 1);
        if (t1 == -1 || t2 == -1)
            t1 = ~t2 ? t2 : t1, t2 = ~t1 ? t1 : t2;
        print(calc(t1) <= calc(t2) ? t1 : t2);//注意輸出編號小的
    }
    return 0;
}