【第K小数——可持久化权值线段树】

发布于:2025-03-18 ⋅ 阅读:(17) ⋅ 点赞:(0)

题目

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;

int a[N], b[N];
int n, m, len;
int rt[N], idx; // idx 是点分配器

struct node
{
    int l, r;
    int s;
} tr[N * 22];

int getw(int x)
{
    return lower_bound(b + 1, b + len + 1, x) - b;
}

int build(int l, int r)
{
    int p = ++idx;
    tr[p].s = 0; // 初始化 s

    if (l < r)
    {
        int mid = l + r >> 1;
        tr[p].l = build(l, mid);
        tr[p].r = build(mid + 1, r);
    }
    return p;
}

int insert(int x, int l, int r, int v)
{
    int p = ++idx;
    tr[p] = tr[x];
    tr[p].s++; // 更新 s

    if (l < r)
    {
        int mid = l + r >> 1;
        if (v <= mid) tr[p].l = insert(tr[x].l, l, mid, v);
        else tr[p].r = insert(tr[x].r, mid + 1, r, v);
    }
    return p;
}

int query(int x, int y, int l, int r, int k)
{
    if (l == r) return l;

    int mid = l + r >> 1;
    int s = tr[tr[x].l].s - tr[tr[y].l].s; // 左子树的节点数
    if (k <= s) return query(tr[x].l, tr[y].l, l, mid, k);
    else return query(tr[x].r, tr[y].r, mid + 1, r, k - s);
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]), b[i] = a[i];

    sort(b + 1, b + n + 1);
    len = unique(b + 1, b + n + 1) - b - 1; // 初始化全局变量 len

    rt[0] = build(1, len); // 使用 len 作为区间范围
    for (int i = 1; i <= n; i++)
        rt[i] = insert(rt[i - 1], 1, len, getw(a[i])); // 更新 rt[i]

    while (m--)
    {
        int l, r, k;
        scanf("%d%d%d", &l, &r, &k);
        printf("%d\n", b[query(rt[r], rt[l - 1], 1, len, k)]); // 映射回 b,相对大小(位置)映射回实际大小
    }
    return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到