没错是的,终于是放下了心中的一块石头,过了初赛了。庆祝一下庆祝一下。好,那不说废话,上主题。主席树,问题是有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-