poj 2104 可持久化线段树

  我们先离散化,然后根据权值建立线段树,假设我们现在有一颗权值线段树,表示在区间1-n中每个数出现了几次,那么我们可以二分的求出来这个区间的k大值,类似sbt的select操作,那么因为点的权值插入是无序的,所以我们并不能对于子区间l,r做上述操作,因为我们无法提出这个区间,那么我们建立可持久化线段树就好了。

  反思:第一次写可持久化数据结构,自己yy着写的,开始没注意到新建节点的时候节点的值就应该是上一棵线段树中该节点对应节点的值+1,而是维护的这个值,就导致了各种重复计算问题= =。

  

//By BLADEVIL

#include <cstdio>

#include <cstring>

#include <algorithm>

#define maxn 100010



using namespace std;



struct segment {

    int left,right,sum;

    int son[2];

    segment(){

        left=right=sum=0;

        memset(son,0,sizeof son);

    }

}t[maxn<<5];



struct rec {

    int num,key;

}a[maxn];



int n,m,tot;

int rot[maxn],ans[maxn];



bool cmp1(rec x,rec y) {

    return x.key<y.key;

}



bool cmp2(rec x,rec y) {

    return x.num<y.num;

}



void build(int &x,int l,int r) {

    if (!x) x=++tot;

    t[x].left=l; t[x].right=r;

    if (l==r) return ;

    int mid=t[x].left+t[x].right>>1;

    build(t[x].son[0],l,mid); build(t[x].son[1],mid+1,r);

}



void insert(int &x,int rot,int y,int l,int r) {

    if (!x) x=++tot;

    t[x].left=l; t[x].right=r;

    if (l==r) {

        t[x].sum=t[rot].sum+1; return ;

    }

    int mid=t[x].left+t[x].right>>1;

    if (y>mid) {

        insert(t[x].son[1],t[rot].son[1],y,mid+1,r);

        t[x].son[0]=t[rot].son[0];

        //t[t[x].son[0]].sum=t[t[t[x].son[0]].son[0]].sum+t[t[t[x].son[0]].son[1]].sum;

    } else {

        insert(t[x].son[0],t[rot].son[0],y,l,mid);

        t[x].son[1]=t[rot].son[1];

        //t[t[x].son[1]].sum=t[t[t[x].son[1]].son[0]].sum+t[t[t[x].son[1]].son[1]].sum;

    }

    t[x].sum=t[rot].sum+1;

}



int ask(int lx,int rx,int k) {

    //printf("|%d %d %d\n",lx,rx,k);

    if (t[lx].left==t[lx].right) return t[lx].left;

    if (k>t[t[rx].son[0]].sum-t[t[lx].son[0]].sum) 

        return ask(t[lx].son[1],t[rx].son[1],k-t[t[rx].son[0]].sum+t[t[lx].son[0]].sum); else 

        return ask(t[lx].son[0],t[rx].son[0],k);

}



int main() {

    scanf("%d%d",&n,&m);

    for (int i=1;i<=n;i++) scanf("%d",&a[i].key),a[i].num=i;

    sort(a+1,a+1+n,cmp1);

    int j=1; ans[1]=a[1].key;

    for (int i=1,cur=a[1].key;i<=n;i++)

        if (a[i].key==cur) a[i].key=j; else cur=a[i].key,a[i].key=++j,ans[j]=cur;

    //for (int i=1;i<=n;i++) printf("%d %d\n",a[i].num,a[i].key);

    sort(a+1,a+1+n,cmp2);

    build(rot[0],1,j);

    for (int i=1;i<=n;i++) insert(rot[i],rot[i-1],a[i].key,1,j);

    //for (int i=1;i<=tot;i++) printf("%d %d %d %d %d %d\n",i,t[i].son[0],t[i].son[1],t[i].left,t[i].right,t[i].sum);

    for (int i=1;i<=m;i++) {

        int l,r,k; scanf("%d%d%d",&l,&r,&k);

        printf("%d\n",ans[ask(rot[l-1],rot[r],k)]);

    }

    //for (int i=1;i<=j;i++) printf("%d ",ans[i]); printf("\n");

    //for (int i=1;i<=n;i++) printf("%d ",a[i].key); printf("\n");

    return 0;

}

 

你可能感兴趣的:(poj)