洛谷P4559 [JSOI2018] 列队 题解 可持久化线段树

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

解题思路:完全来自 小粉兔 大佬的博客

示例程序:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 5e5 + 5, maxm = 3e7, INF = 1.5e6 + 5;

#define ls(u) tr[u].l
#define rs(u) tr[u].r

struct Node {
    int l, r, cnt;
    ll sum;
} tr[maxm];

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

int rt[maxn], idx;

void build(int val, int l, int r, int p, int &u) {
    if (!u) u = ++idx;
    if (l == r) {
        tr[u].cnt++;
        tr[u].sum += val;
        return;
    }
    int mid = (l + r) >> 1;
    if (val <= mid) {
        build(val, l, mid, ls(p), ls(u));
        rs(u) = rs(p);
    }
    else {
        ls(u) = ls(p);
        build(val, mid+1, r, rs(p), rs(u));
    }
    push_up(u);
}

int n, m, a[maxn];

ll query(int L, int R, int l, int r, int u1, int u2) {
    if (!u2) return 0;
    int cnt = tr[u2].cnt - tr[u1].cnt;
    ll sum = tr[u2].sum - tr[u1].sum;
    if (r <= L) { // 全都往右跑
        return 1ll * (L + L + cnt-1) * cnt / 2 - sum;
    }
    if (l >= R) { // 全都往左跑
        return sum - 1ll * (L + L + cnt-1) * cnt / 2;
    }
    int cnt_l = tr[ls(u2)].cnt - tr[ls(u1)].cnt, mid = (l + r) >> 1;
    return query(L, L+cnt_l-1, l, mid, ls(u1), ls(u2)) + query(L+cnt_l, R, mid+1, r, rs(u1), rs(u2));
}

ll cal(int L, int R, int K) {
    return query(K, K+R-L, 0, INF, rt[L-1], rt[R]);
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", a+i);
        build(a[i], 0, INF, rt[i-1], rt[i]);
    }
    for (int i = 0, l, r, K; i < m; i++) {
        scanf("%d%d%d", &l, &r, &K);
        ll ans = cal(l, r, K);
        printf("%lld\n", ans);
    }
    return 0;
}
posted @ 2026-07-19 13:32  quanjun  阅读(4)  评论(0)    收藏  举报