#線段樹、樹狀陣列#D 籌備計劃
阿新 • • 發佈:2020-10-13
分析
首先這個位置應該是帶權中位數\((\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; }