线段树分裂

P5494 【模板】线段树分裂
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10, MAXV = MAXN * 200;
int n, m, rt[MAXN], ls[MAXV], rs[MAXV], idx, cnt = 1;
ll tr[MAXV];
inline void pu(int x) { tr[x] = tr[ls[x]] + tr[rs[x]]; }
void add(int &x, int l, int r, int p, ll v)
{
    if (!x) x = ++idx;
    tr[x] += v;
    if (l == p && p == r) return;
    int mid = (l + r) >> 1;
    if (p <= mid)
        add(ls[x], l, mid, p, v);
    else
        add(rs[x], mid + 1, r, p, v);
    pu(x);
}
ll qsum(int x, int l, int r, int pl, int pr)
{
    if (!x) return 0;
    if (pl <= l && r <= pr) return tr[x];
    int mid = (l + r) >> 1;
    ll res = 0;
    if (pl <= mid) res += qsum(ls[x], l, mid, pl, pr);
    if (mid < pr) res += qsum(rs[x], mid + 1, r, pl, pr);
    return res;
}
int qrnk(int x, int l, int r, ll k)
{
    if (l == r) return l;
    if (k > tr[x]) return -1;
    int mid = (l + r) >> 1;
    if (k <= tr[ls[x]])
        return qrnk(ls[x], l, mid, k);
    else
        return qrnk(rs[x], mid + 1, r, k - tr[ls[x]]);
}
int merge(int x, int y, int l, int r)
{
    if (!x || !y) return x | y;
    if (l == r)
    {
        tr[x] += tr[y];
        return x;
    }
    int mid = (l + r) >> 1;
    ls[x] = merge(ls[x], ls[y], l, mid);
    rs[x] = merge(rs[x], rs[y], mid + 1, r);
    pu(x);
    return x;
}
void split(int &x, int &y, int l, int r, int pl, int pr)
{
    if (!x) return;
    if (pl <= l && r <= pr)
    {
        y = x;
        x = 0;
        return;
    }
    if (!y) y = ++idx;
    int mid = (l + r) >> 1;
    if (pl <= mid) split(ls[x], ls[y], l, mid, pl, pr);
    if (mid < pr) split(rs[x], rs[y], mid + 1, r, pl, pr);
    pu(x);
    pu(y);
}
int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int x, i = 1; i <= n; i++) cin >> x, add(rt[cnt], 1, n, i, x);
    while (m--)
    {
        int op, p, x, y, t, q, k;
        cin >> op;
        switch (op)
        {
            case 0:
                cin >> p >> x >> y;
                split(rt[p], rt[++cnt], 1, n, x, y);
                break;
            case 1:
                cin >> p >> t;
                rt[p] = merge(rt[p], rt[t], 1, n);
                break;
            case 2:
                cin >> p >> x >> q;
                add(rt[p], 1, n, q, x);
                break;
            case 3:
                cin >> p >> x >> y;
                cout << qsum(rt[p], 1, n, x, y) << "\n";
                break;
            case 4:
                cin >> p >> k;
                cout << qrnk(rt[p], 1, n, k) << '\n';
                break;
        }
    }
    return 0;
}