主席树板子

主席树( O ( n l o g n ) O(nlogn) O(nlogn)求区间第k小)

#include <bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;
const int inf = 0x3f3f3f3f;
int t;
int n, m, k;
struct PST
{
    int nn, tot;
    struct node
    {
        int lc, rc, sum;
        node(){}
    };
    vector<node> tr;
    vector<int> roots;
    PST(int n1) : nn(n1), tot(0), tr(1), roots(1, 0) // 如果修改次数为n*2,则将 << 5变成 << 6
    {
        build(1, nn, roots[0]); //初始根节点为0
    }
    #define lc(rt) tr[tr[rt].lc]
    #define rc(rt) tr[tr[rt].rc]
    void push_up(int rt)
    {
        tr[rt].sum = lc(rt).sum + rc(rt).sum;
    }
    void build(int l, int r, int& rt) {
        rt = ++tot;
        tr.emplace_back();
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        int nb1, nb2;
        // build(l, mid, tr[rt].lc);
        // build(mid + 1, r, tr[rt].rc);
        build(l, mid, nb1);
        tr[rt].lc = nb1;
        build(mid + 1, r, nb2);
        tr[rt].rc = nb2;
        push_up(rt);
    }
    void update(int pos, int val, int l, int r, int old, int& rt)
    {
        rt = ++tot;
        tr.emplace_back();
        tr[rt] = tr[old];
        if (l == r)
        {
            tr[rt].sum = tr[old].sum + val;
            return;
        }
        int mid = (l + r) >> 1;
        int nb;
        if (pos <= mid)
        {
            // update(pos, val, l, mid, tr[old].lc, tr[rt].lc);
            update(pos, val, l, mid, tr[old].lc, nb);
            tr[rt].lc = nb;
        }
        else
        {
            // update(pos, val, mid + 1, r, tr[old].rc, tr[rt].rc);
            update(pos, val, mid + 1, r, tr[old].rc, nb);
            tr[rt].rc = nb;
        }
        push_up(rt);
    }
    int update(int pos, int val)
    {
        int new_root;
        update(pos, val, 1, nn, roots.back(), new_root);
        roots.push_back(new_root);
        return new_root;
    }
    int query(int u, int v, int l, int r, int kk)
    {
        if (l == r)
            return l;
        int mid = (l + r) >> 1;
        int x = lc(v).sum - lc(u).sum;
        if (kk <= x)
            return query(tr[u].lc, tr[v].lc, l, mid, kk);
        return query(tr[u].rc, tr[v].rc, mid + 1, r, kk - x);
    }
    int find_kth_smallest_num(int l, int r, int kk)
    {
        return query(roots[l - 1], roots[r], 1, nn, kk);
    }
    int find_kth_biggest_num(int l, int r, int kk)
    {
        int nb = r - l + 1;
        return find_kth_smallest_num(l, r, nb + 1 - kk);
    }
};
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    auto v = a;
    sort(v.begin() + 1, v.end());
    v.erase(unique(v.begin() + 1, v.end()), v.end());
    PST tr(n);
    auto getid = [&](int x)
    {
        return lower_bound(v.begin() + 1, v.end(), x) - v.begin();
    };
    while (m--)
    {
        int l, r, kk;
        cin >> l >> r >> kk;
        cout << v[tr.find_kth_smallest_num(l, r, kk)] << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值