主席树-指针实现-找第k小数

主席树,其实就是N颗线段树

只是他们公用了一部分节点(๑•̀ㅂ•́)و✧

我大部分的代码是从一位大佬的那里看到的

我这个垃圾程序连Poj2104上的数据都过不了TLE

so希望神犇能给我看看,

顺便给和我一样的底层人物一点指针的帮助

也许是 new 太慢了

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100100
using namespace std;
struct XDS{
    int l,r,dat;
    XDS *lc,*rc;
    XDS(){l=r=dat=0,lc=rc=NULL;}
};XDS *ro[N];
int n,qn,num[N],val[N],len;
void prerun(){//这是离散化的预处理 
    sort(val+0,val+n);
    len=unique(val+0,val+n)-val;
}
int fvind(int x){//离散化get 
    return lower_bound(val+0,val+len,x)-val+1;
}
void Empty_total(XDS *&rt,int l,int r){//以l为左,r为右处理一颗空树,初始化 
    rt=new XDS();
    rt->l=l;
    rt->r=r;
    if(l==r)return ;
    int mid=(l+r)/2;
    Empty_total(rt->lc,l,mid);
    Empty_total(rt->rc,mid+1,r);
}
void dfs(XDS *rt){//调试用的,不用管
    if(rt==NULL)return;
    cout<<rt<<" "<<rt->l<<" "<<rt->r<<" "<<rt->dat<<"
";
    dfs(rt->lc);
    dfs(rt->rc);
}
void add(XDS *his,XDS *&nrt,int v){//his:从上一个转移过来,nrt :现在在搞的 (同位转移)增加一个|V:离散化后 
    if(his==NULL)return ;//结束 
    if(nrt==NULL)nrt=new XDS();//新开节点
    int l=his->l;nrt->l=l;
    int r=his->r;nrt->r=r;
    if(l==r){
        nrt->dat=his->dat+1;
        return ;
    }
    int mid=(l+r)/2;
    if(v<=mid){//值在左侧 
        nrt->rc=his->rc;//直接拿右侧 
        add(his->lc,nrt->lc,v);//查左 
    }
    else{//值在右侧 
        nrt->lc=his->lc;//直接拿左侧 
        add(his->rc,nrt->rc,v);//查右 
    }
    nrt->dat=nrt->lc->dat+nrt->rc->dat;
}
int query(XDS *lrt,XDS *rrt,int k){//在lrt与rrt之间查第K大 
    int l=1,r=len;//二分查找
    while(l<r){
        int mid=(l+r)/2;
        int cnt=rrt->lc->dat-lrt->lc->dat;/*两个树的左子树差
        即在这个区间内在[0,mid]范围内的增加值 */
        if(cnt>=k){//比k个多,往左搜 
            r=mid;
            lrt=lrt->lc;
            rrt=rrt->lc;//同步浏览 
        }
        else {//比k个少,往右 
            l=mid+1;
            k-=cnt;
            lrt=lrt->rc;
            rrt=rrt->rc;
        }
    }
    return l;
}
int main(){
    scanf("%d%d",&n,&qn);
    for(int i=1;i<=n;i++){
        scanf("%d",&num[i]);
        val[i-1]=num[i];
    }
    prerun(); 
    Empty_total(ro[0],1,len);
//    dfs(ro[0]);
    for(int i=1;i<=n;i++){
        add(ro[i-1],ro[i],fvind(num[i]));
    }
    int a,b,c;
    for(int i=1;i<=qn;i++){
        scanf("%d%d%d",&a,&b,&c);
//        cout<<query(ro[a-1],ro[b],c)<<endl;
        printf("%d
",val[query(ro[a-1],ro[b],c)-1]);
    }
    return 0;
}
Miemeng真的蒻
原文地址:https://www.cnblogs.com/kalginamiemeng/p/11008306.html