P5494 【模板】线段树分裂

题目链接:https://www.luogu.com.cn/problem/P5494

解题思路:来自 oi.wiki

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5, maxm = maxn * 30;

long long tr[maxm];
int n, m, rt[maxm], ls[maxm], rs[maxm], idx, rub[maxm], idx2, idx3 = 1;
// idx: 新建节点个数; idx2: 垃圾站中节点个数; idx3: 可重集个数

int New() {
    return idx2 ? rub[idx2--] : ++idx;
}

void Del(int &u) {
    ls[u] = rs[u] = tr[u] = 0;
    rub[++idx2] = u;
    u = 0;
}

void push_up(int u) {
    tr[u] = tr[ ls[u] ] + tr[ rs[u] ];
}

void build(int l, int r, int &u) {
    if (!u)
        u = New();
    if (l == r) {
        scanf("%lld", tr+u);
        return;
    }
    int mid = l + r >> 1;
    build(l, mid, ls[u]);
    build(mid+1, r, rs[u]);
    push_up(u);
}

int Merge(int l, int r, int a, int b) {
    if (!a || !b) return a + b;
    if (l == r) {
        tr[a] += tr[b];
        Del(b);
        return a;
    }
    int mid = l + r >> 1;
    ls[a] = Merge(l, mid, ls[a], ls[b]);
    rs[a] = Merge(mid+1, r, rs[a], rs[b]);
    Del(b);
    push_up(a);
    return a;
}

void Split(int L, int R, int l, int r, int &a, int &b) {
    if (r < L || R < l)
        return;
    if (!a)
        return;
    if (L <= l && r <= R) {
        b = a;
        a = 0;
        return;
    }
    if (!b)
        b = New();
    int mid = l + r >> 1;
    if (L <= mid) Split(L, R, l, mid, ls[a], ls[b]);
    if (R > mid) Split(L, R, mid+1, r, rs[a], rs[b]);
    push_up(a);
    push_up(b);
}

void add(int p, int v, int l, int r, int &u) {
    if (!u)
        u = New();
    if (l == r) {
        tr[u] += v;
        return;
    }
    int mid = l + r >> 1;
    (p <= mid) ? add(p, v, l, mid, ls[u]) : add(p, v, mid+1, r, rs[u]);
    push_up(u);
}

long long query(int L, int R, int l, int r, int u) {
    if (!u)
        return 0;
    if (L <= l && r <= R)
        return tr[u];
    int mid = l + r >> 1;
    long long res = 0;
    if (L <= mid) res += query(L, R, l, mid, ls[u]);
    if (R > mid) res += query(L, R, mid+1, r, rs[u]);
    return res;
}

int kth(int k, int l, int r, int u) {
    if (tr[u] < k) return -1;
    if (l == r)
        return l;
    int mid = l + r >> 1;
    long long num = tr[ ls[u] ];
    return (k <= num) ? kth(k, l, mid, ls[u]) : kth(k-num, mid+1, r, rs[u]);
}

int main() {
    scanf("%d%d", &n, &m);
    build(1, n, rt[1]);
    while (m--) {
        int op;
        scanf("%d", &op);
        if (op == 0) {  // 0 p x y
            int p, x, y;
            scanf("%d%d%d", &p, &x, &y);
            Split(x, y, 1, n, rt[p], rt[++idx3]);
        }
        else if (op == 1) { // 1 p t
            int p, t;
            scanf("%d%d", &p, &t);
            rt[p] = Merge(1, n, rt[p], rt[t]);
        }
        else if (op == 2) { // 2 p x q
            int p, x, q;
            scanf("%d%d%d", &p, &x, &q);
            add(q, x, 1, n, rt[p]);
        }
        else if (op == 3) { // 3 p x y
            int p, x, y;
            scanf("%d%d%d", &p, &x, &y);
            long long ans = query(x, y, 1, n, rt[p]);
            printf("%lld\n", ans);
        }
        else {  // 4 p k
            int p, k;
            scanf("%d%d", &p, &k);
            int ans = kth(k, 1, n, rt[p]);
            printf("%d\n", ans);
        }
    }
    return 0;
}
posted @ 2026-03-19 19:11  quanjun  阅读(2)  评论(0)    收藏  举报