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这个版本的信息),也没想象的那么难。