主席树-指针实现-找第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真的蒻

浙公网安备 33010602011771号