码迷,mamicode.com
首页 > 其他好文 > 详细

主席树

时间:2019-07-30 18:42:18      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:return   main   src   ace   math   XML   主席树   height   add   

我们一开始要建一棵空线段树,然后一个一个的添加线段树。加入线段树后会是这样:
技术图片
再加入[1,

技术图片


至此,裸树就建好了,并且只用了O(nlogn)的空间。
查询的时候存两个点,一开始为两个区间的根结点,两结点的差比大小,两个点要同时往左/右跳。

 

#include <bits/stdc++.h>
using namespace std;
int n,q,m;
int a[200010],b[200010];
int root[20001000];
int size[20001000];
int cnt;
int L[20000100],R[20001000];
int build(int l,int r)
{
    int rt=++cnt;
    size[rt]=0;
    if(l==r){        
        return rt;
    }
    int mid=(l+r)/2;
    L[rt]=build(l,mid);
    R[rt]=build(mid+1,r);
    return rt;
}
int add(int pre,int l,int r,int goal)
{
    int rt=++cnt;
    size[rt]=size[pre]+1;
    L[rt]=L[pre];
    R[rt]=R[pre];
    if(l==r){
        return rt;
    }
    int mid=(l+r)/2;
    if(goal<=mid) L[rt]=add(L[pre],l,mid,goal);
    else{
        R[rt]=add(R[pre],mid+1,r,goal);
    }
    return rt;
}
int query(int u,int v,int l,int r,int goal)
{
    if(l>=r) return l;
    int tmp=size[L[v]]-size[L[u]];
    int mid=(l+r)/2;
    if(tmp>=goal) return query(L[u],L[v],l,mid,goal);
    else{
        return query(R[u],R[v],mid+1,r,goal-tmp);
    }
    
}
int main ()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    m=unique(b+1,b+1+n)-b-1;
    root[0]=build(1,m);
    for(int i=1;i<=n;i++){
        int tmp=lower_bound(b+1,b+1+m,a[i])-b;
        root[i]=add(root[i-1],1,m,tmp);
    }
    for(int i=1;i<=q;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        int tmp=query(root[x-1],root[y],1,m,z);
        printf("%d\n",b[tmp]);
    }
}

 

主席树

标签:return   main   src   ace   math   XML   主席树   height   add   

原文地址:https://www.cnblogs.com/kamimxr/p/11271945.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!