poj2104 求区间第k大 可持久化线段树

poj2104 求区间第k大  可持久化线段树

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=100100;
const int INF=1e9+10;

int n,m;
int L,R,k;
int a[maxn],b[maxn],bn;
struct SegTree
{
    int l,r;
    int ls,rs;
    int sum;
    void debug()
    {
        printf("l=%2d r=%2d ls=%2d rs=%2d sum=%2d\n",l,r,ls,rs,sum);
    }
};SegTree T[maxn*64];
int root[maxn],tot;

void push_up(int rt)
{
    T[rt].sum=T[T[rt].ls].sum+T[T[rt].rs].sum;
}

int build(int l,int r)
{
    int k=++tot;
    T[k].l=l;T[k].r=r;
    T[k].ls=-1;T[k].rs=-1;
    T[k].sum=0;
    if(l==r) return k;
    int m=(l+r)>>1;
    T[k].ls=build(l,m);
    T[k].rs=build(m+1,r);
    push_up(k);
    return k;
}

int update(int rt,int p,int c)
{
    int k=++tot;
    T[k]=T[rt];
    if(T[rt].l==T[rt].r){
        T[k].sum+=c;
        return k;
    }
    int m=(T[rt].l+T[rt].r)>>1;
    if(p<=m) T[k].ls=update(T[rt].ls,p,c);
    else T[k].rs=update(T[rt].rs,p,c);
    push_up(k);
    return k;
}

int query(int s,int t,int k)
{
    if(T[s].l==T[s].r) return T[s].l;
    int cnt=T[T[s].ls].sum-T[T[t].ls].sum;
    if(k<=cnt) return query(T[s].ls,T[t].ls,k);
    else return query(T[s].rs,T[t].rs,k-cnt);
}

int main()
{
    freopen("in.txt","r",stdin);
    while(cin>>n>>m){
        REP(i,1,n) scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+n+1);
        bn=unique(b+1,b+n+1)-(b+1);
        REP(i,1,n) a[i]=lower_bound(b+1,b+bn+1,a[i])-b;
        tot=0;
        root[0]=build(1,bn);
        REP(i,1,n){
            root[i]=update(root[i-1],a[i],1);
        }
        while(m--){
            scanf("%d%d%d",&L,&R,&k);
            int kth=query(root[R],root[L-1],k);
            printf("%d\n",b[kth]);
        }
    }
    return 0;
}
View Code

 

你可能感兴趣的:(poj2104 求区间第k大 可持久化线段树)