P3834 模板可持久化线段树 1(主席树)

Posted bigyellowdog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3834 模板可持久化线段树 1(主席树)相关的知识,希望对你有一定的参考价值。

P3834 【模板】可持久化线段树 1(主席树)

Description

  • 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。

Input

  • 第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。

    第二行包含N个整数,表示这个序列各项的数字。

    接下来M行每行包含三个整数l,r,k , 表示查询区间[l,r]内的第k小值。

Outupt

  • 输出包含k行,每行1个整数,依次表示每一次查询的结果

Sample Input

5 5
25957 6405 15770 26287 26465 
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1

Sample Output

6405
15770
26287
25957
26287

Data Size

  • 对于100%的数据满足:1≤N,M≤2?10^5

    对于数列中的所有数ai,均满足?10^9≤ai≤10^9

题解:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 200005
using namespace std;

struct T {int l, r, sum;} t[N << 5];
int n, m, dex, cnt;
int a[N], b[N], r[N];

int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return x *= f;
}

int find(int x) {
    return lower_bound(b + 1, b + 1 + cnt, x) - b;
}

int build(int l, int r)
{
    int p = ++dex, mid = l + r >> 1;
    if(l == r) return p;
    t[p].l = build(l, mid);
    //注意此处不能将p改成++dex然后删去now变量。
    //因为一直往下递归会一直改变dex的值,从而使得给t[p].r赋值时会出错。
    t[p].r = build(mid + 1, r);
    return p;
}

int upd(int las, int l, int r, int val)
{
    int p = ++dex, mid = l + r >> 1;
    t[p].l = t[las].l, t[p].r = t[las].r;
    t[p].sum = t[las].sum + 1;
    if(l == r) return p;
    if(val <= mid) t[p].l = upd(t[las].l, l, mid, val);
    else t[p].r = upd(t[las].r, mid + 1, r, val);
    return p;
}

int ask(int u, int v, int l, int r, int rank)
{
    if(l == r) return l;
    int size = t[t[v].l].sum - t[t[u].l].sum, mid = l + r >> 1;
    if(rank <= size) return ask(t[u].l, t[v].l, l, mid, rank);
    else return ask(t[u].r, t[v].r, mid + 1, r, rank - size);
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        a[i] = read(), b[++cnt] = a[i];
    sort(b + 1, b + 1 + cnt);
    cnt = unique(b + 1, b + 1 + cnt) - b - 1;
    r[0] = build(1, cnt);
    for(int i = 1; i <= n; i++)
        r[i] = upd(r[i - 1], 1, cnt, find(a[i]));
    for(int i = 1; i <= m; i++)
    {
        int ll = read(), rr = read(), rank = read();
        printf("%d
", b[ask(r[ll - 1], r[rr], 1, cnt, rank)]);
    }
    return 0;
}

以上是关于P3834 模板可持久化线段树 1(主席树)的主要内容,如果未能解决你的问题,请参考以下文章

LUOGU P3834 模板可持久化线段树 1(主席树)

P3834 模板可持久化线段树 1(主席树)

P3834 模板可持久化线段树 1(主席树)

P3834 模板可持久化线段树 1(主席树)

p3834 可持久化线段树模板(主席树)

P3834 模板可持久化线段树 1(主席树)