主席树

2024-08-15

主席树是一种可持久化的线段树

#include <bits/stdc++.h>
#define io cin.tie(0), cout.tie(0), ios::sync_with_stdio(false)
#define LL long long
#define ULL unsigned long long
#define EPS 1e-8
#define INF 0x7fffffff
#define SUB -INF - 1
using namespace std;
const int N = 200010;
int cnt = 0;
int a[N], b[N], root[N];
struct
{
    int L, R, sum;
} tree[N << 5];
int build(int pl, int pr)
{
    int rt = ++cnt;
    tree[rt].sum = 0;
    int mid = (pl + pr) >> 1;
    if (pl < pr)
    {
        tree[rt].L = build(pl, mid);
        tree[rt].R = build(mid + 1, pr);
    }
    return rt;
}
int update(int pre, int pl, int pr, int x)
{
    int rt = ++cnt;
    tree[rt].L = tree[pre].L;
    tree[rt].R = tree[pre].R;
    tree[rt].sum = tree[pre].sum + 1;
    int mid = (pl + pr) >> 1;
    if (pl < pr)
    {
        if (x <= mid)
            tree[rt].L = update(tree[pre].L, pl, mid, x);
        else
            tree[rt].R = update(tree[pre].R, mid + 1, pr, x);
    }
    return rt;
}
int query(int u, int v, int pl, int pr, int k)
{
    if (pl == pr)
        return pl;
    int x = tree[tree[v].L].sum - tree[tree[u].L].sum;
    int mid = (pl + pr) >> 1;
    if (x >= k)
        return query(tree[u].L, tree[v].L, pl, mid, k);
    else
        return query(tree[u].R, tree[v].R, mid + 1, pr, k - x);
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        b[i] = a[i];
    }
    sort(b + 1, b + 1 + n);
    int size = unique(b + 1, b + 1 + n) - b - 1;
    for (int i = 0; i <= n; i++)
    {
        int x = lower_bound(b + 1, b + 1 + size, a[i]) - b;
        root[i] = update(root[i - 1], 1, size, x);
    }
    while (m--)
    {
        int x, y, k;
        scanf("%d%d%d", &x, &y, &k);
        int t = query(root[x - 1], root[y], 1, size, k);
        printf("%d\n", b[t]);
    }
    return 0;
}