模板——主席树
没错是的,终于是放下了心中的一块石头,过了初赛了。庆祝一下庆祝一下。好,那不说废话,上主题。主席树,问题是有T个序列,每个序列分别有ni个数
对于每个序列mi次询问,每次询问有l,r,k,表示求在序列中l到r区间的第k大的数
输入:第一行T表示有T个序列,然后有n,m分别表示序列有n个数,m次询问,接下来m行有l,r,k意义如上;
没错这个东西啃了我一天,最后终于明白了是什么意思,我果然还是太年轻了,还应当多加锻炼。希望你们有毅力能啃下去(当然可能是我太蠢)
#include<bits/stdc++.h>
const int N=100000+5;
using namespace std;
int a[N],b[N],root[N*20],leson[N*20],rison[N*20],sum[N*20],T,n,m,size;
//leson[i]表示i节点的左儿子,rison[i]表示i节点的右儿子
int tot=0;
void build(int &x,int l,int r){//注意取址 是&x x=++tot的时候这个地址的变量也会改变
x=++tot;
sum[x]=0;
if (l==r) return ;
int mid=(l+r)>>1;
build(leson[x],l,mid);
build(rison[x],mid+1,r);
}
void updata(int &x,int l,int r,int last,int num){
x=++tot;
leson[x]=leson[last];
rison[x]=rison[last];
sum[x]=sum[last]+1;
if (l==r) return ;
int mid=(l+r)>>1;
if (num<=mid) updata(leson[x],l,mid,leson[last],num);
else updata(rison[x],mid+1,r,rison[last],num);
}
int query(int ss,int tt,int l,int r,int k){
if (l==r) return l;
int mid=(l+r)>>1;
int cnt=sum[leson[tt]]-sum[leson[ss]];//leson和rison表示的区间长短一定相同
if (k<=cnt) return query(leson[ss],leson[tt],l,mid,k);
else return query(rison[ss],rison[tt],mid+1,r,k-cnt);
}
void work(){
int ql,qr,x;
cin>>ql>>qr>>x;
int pos=query(root[ql-1],root[qr],1,size,x);
cout<<b[pos]<<endl;
}
int main(){
cin>>T;
while (T--){
cin>>n>>m;
for (int i=1; i<=n; i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
size=unique(b+1,b+1+n)-b-1;//unique是去重函数,返回去重后的尾地址
tot=0;
build(root[0],1,size);
for (int i=1; i<=n; i++) a[i]=lower_bound(b+1,b+1+size,a[i])-b;
for (int i=1; i<=n; i++)
updata(root[i],1,size,root[i-1],a[i]);
for (int i=1; i<=m; i++)
work();
}
return 0;
}
模板摘自某博主,这位博主讲的挺详细的,而且更容易理解
made by cain-

浙公网安备 33010602011771号