模板——主席树

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

posted @ 2017-10-19 08:17  |斗蜂|  阅读(153)  评论(0编辑  收藏  举报