主席树-指针实现-找第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<<"\n"; 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\n",val[query(ro[a-1],ro[b],c)-1]); } return 0; }
Miemeng真的蒻