主席树模板

可持久化线段树 

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

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)

using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=200005;
int sum[maxn<<5],L[maxn<<5],R[maxn<<5];
int n,m,cnt,a[maxn],T[maxn],b[maxn];

inline int build(int l,int r)
{
    int rt=++cnt;
    if(l<r)
    {
        //空,所以sum为0 
        int mid=(l+r)>>1;
        L[rt]=build(l,mid);
        R[rt]=build(mid+1,r);    
    }
    re rt;
}


inline int modify(int pre,int l,int r,int x)
{
    int rt=++cnt;//重新建点,维护此次链 
    L[rt]=L[pre];R[rt]=R[pre];sum[rt]=sum[pre]+1;//移花接木,复制前章 
    if(l==r)re rt;//返回此次修改 
    int mid=(l+r)>>1;
    if(x<=mid)L[rt]=modify(L[pre],l,mid,x);
    else R[rt]=modify(R[pre],mid+1,r,x);//分区 
    re rt;
}

inline int query(int pre,int now,int l,int r,int x)
{
    if(l==r)re l;
    int k=sum[L[now]]-sum[L[pre]];//左区间相减 
    int mid=(l+r)>>1;
    if(k>=x)re query(L[pre],L[now],l,mid,x);//是否在左区间内 
    else re query(R[pre],R[now],mid+1,r,x-k);
}


int main()
{
    freopen("in.txt","r",stdin);
    int x,y,z;
    rd(n),rd(m);
    inc(i,1,n)
    {
        rd(a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    int N=unique(b+1,b+n+1)-b-1;
    //去重排序 
    
    T[0]=build(1,N);//建立空区间 
     
    inc(i,1,n)
    T[i]=modify(T[i-1],1,N,lower_bound(b+1,b+N+1,a[i])-b);
    //依次加入 
    
    inc(i,1,m)
    {
        rd(x),rd(y),rd(z);
        printf("%d\n",b[query(T[x-1],T[y],1,N,z)]);
    }
    re 0;
}

 

posted @ 2019-08-20 09:03  凉如水  阅读(100)  评论(0编辑  收藏  举报