P3834 【模板】可持久化线段树 (静态主席树)

 

主席树查找和更新时时间空间复杂度均为O(logn),建树2*nlogn, 且空间复杂度约为O(nlogn + nlogn)前者为空树的空间复杂度,后者为更新n次的空间复杂度

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn],v[maxn],rt[maxn],tot,n,nn,q;
struct node
{
    int ls,rs,sum;
    node(int ls=0,int rs=0,int sum=0)
    {
        this->ls=ls,this->rs=rs,this->sum=sum;
    }
}tree[maxn*30];

int build1(int l,int r)
{
    int t=++tot;
    tree[t].sum=0;
    if(l!=r)
    {
        int mid=(l+r)>>1;
        tree[t].ls=build1(l,mid);
        tree[t].rs=build1(mid+1,r);
    }
    return t;
}
int build2(int l,int r,int last,int val)
{
    int t=++tot;
    tree[t]=tree[last];
    tree[t].sum++;
    if(l!=r)
    {
        int mid=(l+r)>>1;
        if(val<=mid)
            tree[t].ls=build2(l,mid,tree[last].ls,val);
        else
            tree[t].rs=build2(mid+1,r,tree[last].rs,val);
    }
    return t;
}
int query(int l,int r,int x,int y,int k)
{
    if(l==r) return l;
    int tmp=tree[tree[y].ls].sum-tree[tree[x].ls].sum,mid=(l+r)>>1;
    if(tmp>=k)
        return query(l,mid,tree[x].ls,tree[y].ls,k);
    else
        return query(mid+1,r,tree[x].rs,tree[y].rs,k-tmp);
}
int getval(int x)
{
    return lower_bound(v+1,v+nn+1,x)-v;
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
        scanf("%d",&(a[i])),v[i]=a[i];
    sort(v+1,v+n+1);
    nn=unique(v+1,v+n+1)-v-1;
    rt[0]=build1(1,nn);
    for(int i=1;i<=n;i++)
        rt[i]=build2(1,nn,rt[i-1],getval(a[i]));
    while(q--)
    {
        int x,y,k;
        scanf("%d%d%d",&x,&y,&k);
        printf("%d\n",v[query(1,nn,rt[x-1],rt[y],k)]);
    }
    return 0;
}

学了之后才发现,可持久化线段树就是把1到n每个位置都开了一个权值线段树(每个权值线段树都代表了1至i这个版本的信息),也没想象的那么难。

posted @ 2019-04-30 17:56  eason99  阅读(78)  评论(0编辑  收藏  举报