主席树模板poj 2104

资料1:http://blog.csdn.net/regina8023/article/details/41910615
资料2:模板来源:http://www.cnblogs.com/lidaxin/category/794693.html

主席树主要是维护区间在第i个数插入之后,每个区间内的数出现的次数,这样就需要维护n颗线段树。
可持久化在于它可以保存前面任意第i个数插入时的区间情况
同时每颗树结构都是一样的,因此可以相减得到特定区间的情况

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ll long long
#define inf 1000000000LL
#define mod 1000000007
using namespace std;
ll read()
{
    ll x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
const int N=1e5+10;
const int M=N*20+10;
int tot,sz;
int root[N],ls[M],rs[M];
ll sum[M];
int v[N],ha[N];
void update(int l,int r,int x,int &y,int v)
{
    y=++sz;
    sum[y]=sum[x]+1;
    if(l==r)return;
    ls[y]=ls[x];rs[y]=rs[x];
    int mid=(l+r)>>1;
    if(v<=mid)update(l,mid,ls[x],ls[y],v);
    else update(mid+1,r,rs[x],rs[y],v);
}
int que(int L,int R,int rk)
{
    int l=1,r=tot,mid,x,y;
    x=root[L-1];y=root[R];
    while(l<r)
    {
        int mid=(l+r)>>1;
        int now=sum[ls[y]]-sum[ls[x]];
        if(rk<=now) r=mid,x=ls[x],y=ls[y];
        else l=mid+1,rk-=now,x=rs[x],y=rs[y];
    }
    return ha[l];
}

int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;i++)
        v[i]=read(),ha[i]=v[i];
    sort(ha+1,ha+1+n);
    tot=unique(ha+1,ha+1+n)-ha-1;
    for(int i=1;i<=n;i++)
        v[i]=lower_bound(ha+1,ha+1+tot,v[i])-ha;
    for(int i=1;i<=n;i++)
        update(1,tot,root[i-1],root[i],v[i]);
    int x,y,z;
    for(int i=1;i<=m;i++) {
        x=read(),y=read(),z=read();
        printf("%d\n",que(x,y,z));
    }
    return 0;
}
posted @ 2017-05-31 19:35  江南何采莲  阅读(106)  评论(0编辑  收藏  举报