可持久化线段树——主席树

前言:
最近心(po)血(yu)来(ya)潮(li)学习了一下主席树。
主席树,即可持久化线段树,支持维护和查询区间的第\(k\)大、区间不同种类个数等,基于线段树的思想之上

结构分析:

主席树会维护每次加入时通过点的个数(可以理解为,一颗弹珠从树根)
下面来张动图(PowerPoint冠名

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define f(x,y) for(register int i=x;i<=y;i++)
#define G ch=getchar()
#define rd int
#define in(x) x=read();
#define node int
#define mid ((l+r)>>1)
#define fm(x) memset(x,0,sizeof(x))
#define maxN 200000
using namespace std;
inline rd read();
class president_tree
{
    public:
        node query(int x,int y,int w) {return rank[_query(root[x-1],root[y],1,_size,w)];}
        void build(int a[],int n)
        {
            tot=0; fm(rank); fm(root); fm(sum); fm(L); fm(R);
            for(register int i=1;i<=n;i++) rank[i]=a[i];
            sort(rank+1,rank+n+1);
            _size=unique(rank+1,rank+n+1)-rank-1;
            root[0]=_build(1,_size);
            for(register int i=1;i<=n;i++)
                root[i]=update(root[i-1],1,_size,lower_bound(rank+1,rank+_size+1,a[i])-rank);
        }
        node update(int pre,int l,int r,int w)
        {
            int k=++tot; L[k]=L[pre]; R[k]=R[pre]; sum[k]=sum[pre]+1;
            if(l<r)
                if(w<=mid) L[k]=update(L[pre],l,mid,w);
                else R[k]=update(R[pre],mid+1,r,w);
            return k;
        }
        node _query(int u,int v,int l,int r,int k)
        {
            if(l>=r) return l;
            int w=sum[L[v]]-sum[L[u]];
            if(w>=k) return _query(L[u],L[v],l,mid,k);
            else return _query(R[u],R[v],mid+1,r,k-w);
        }
    private:
        int tot,_size;
        node rank[maxN+1],root[maxN+1],sum[(maxN<<5)+1],L[(maxN<<5)+1],R[(maxN<<5)+1];;
        node _build(int l,int r)
        {
            int k=++tot; sum[k]=0;
            if(l<r)
            {
                L[k]=_build(l,mid);
                R[k]=_build(mid+1,r);
            }
            return k;
        }
};
int n,m,a[maxN+1],b[maxN+1],x,y,w;
president_tree tree;
int main()
{
    in(n); in(m); f(1,n) in(a[i]);
    tree.build(a,n);
    f(1,m)
    {
        in(x); in(y); in(w);
        printf("%d\n",tree.query(x,y,w));
    }
    return 0;
}
inline rd read()
{
    char ch=getchar();
    rd num=0,f=1;
    while((ch<'0' || ch>'9') && ch!='-') G;
    if(ch=='-') {f=-1; G;}
    while(ch>='0' && ch<='9') {num=num*10+ch-'0'; G;}
    return num*f;
}

猜你喜欢

转载自www.cnblogs.com/ezsyshx/p/10403244.html