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

想要妹子点击就送:https://www.luogu.org/problemnew/show/P3834

题目背景

这是个非常经典的主席树入门题——静态区间第K小

数据已经过加强,请使用主席树。同时请注意常数优化

题目描述

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

输入输出格式

输入格式:

 

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

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

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 
5 5
25957 6405 15770 26287 26465 
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
输出样例#1: 
6405
15770
26287
25957
26287

说明

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

const int N=2e5+5;
const int M=50;

int n,m;
int a[N],b[N],bound;
int root[N],cnt_root;
struct Tree
{
    int lson,rson,num;
}tree[N*M];

int read()
{
    char c=getchar();int num=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num;
}

void build(int &root,int l,int r)
{
    root=++cnt_root;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(tree[root].lson,l,mid);
    build(tree[root].rson,mid+1,r);
}

void modify(int pre_root,int &root,int l,int r,int pos)
{
    root=++cnt_root;
    tree[root]=tree[pre_root];
    ++tree[root].num;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    if(pos<=mid)
        modify(tree[pre_root].lson,tree[root].lson,l,mid,pos);
    else
        modify(tree[pre_root].rson,tree[root].rson,mid+1,r,pos);
}

int query(int pre_root,int root,int l,int r,int k)
{
    if(l==r)
        return l;
    int tmp=tree[tree[root].lson].num-tree[tree[pre_root].lson].num;
    int mid=(l+r)>>1;
    if(k<=tmp)
        return query(tree[pre_root].lson,tree[root].lson,l,mid,k);
    else
        return query(tree[pre_root].rson,tree[root].rson,mid+1,r,k-tmp);
}

int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;++i)
        a[i]=read(),b[i]=a[i];
    sort(b+1,b+n+1);
    bound=unique(b+1,b+n+1)-b-1;
    build(root[0],1,bound);
    for(int i=1;i<=n;++i)
    {
        modify(root[i-1],root[i],1,bound,lower_bound(b+1,b+bound+1,a[i])-b);
    }
    for(int i=1,l,r,k;i<=m;++i)
    {
        l=read(),r=read(),k=read();
        printf("%d\n",b[query(root[l-1],root[r],1,bound,k)]);
    }
    return 0;
}

 

posted @ 2018-02-12 16:22  whymhe  阅读(119)  评论(0编辑  收藏  举报