主席树总结

主席树的全称是可持久化权值线段树,即主席树 ⫋ 可持久化线段树。 ——某大佬博客如是云


另一位大佬博客

个人理解

主席树是一棵权值线段树。其节点维护的区间表示值域,储存原数列中有多少数在该值域内。(例如,维护[L~R]的区间的节点,其储存数列中大小在[L~R]之间的数的个数)

对于数列上的每一个位置都建一棵权值线段树,再通过可持久化线段树的克隆节点的操作,在加入一个新位置上的数时,都只新建由于新加入一个数而数值发生改变的节点,从而优化时空间复杂度。

在查询时,利用每棵权值线段树结构相同的性质,通过前缀和来进行指定区间的查询。


洛谷P3834可持久化线段树2

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2e5;
int n,m,cnt,tot;
int a[N],b[N],rt[N];
int sum[30*N],lc[30*N],rc[30*N];//储存每个节点的信息,都要开大30倍 
void build(int &k,int l,int r)
{
	k=++tot;//新建节点 
	if(l==r) return;
	int mid=(l+r)>>1;
	build(lc[k],l,mid);//建左子树 
	build(rc[k],mid+1,r);//建右子树
}
int update(int pre,int l,int r,int p)//pre指向第i-1棵线段树上维护相同区间的节点 
{
	int k=++tot;//新建节点 
	//将pre节点的信息复制到当前节点上;因为当前区间比修改前新增了一个p,所以sum+1
	lc[k]=lc[pre],rc[k]=rc[pre],sum[k]=sum[pre]+1; 
	if(l==r) return k;//叶子节点无需继续向下拓展,直接返回 
	int mid=(l+r)>>1;
	if(p<=mid) lc[k]=update(lc[pre],l,mid,p);//如果左儿子需要修改 
	else rc[k]=update(rc[pre],mid+1,r,p);//如果右儿子需要修改 
	return k;
}
int query(int u,int v,int l,int r,int k)
{
	//设两棵线段树为i和j
	//那么x表示a[i+1]~a[j]的区间内有x个数,其离散化后下标的大小在对应节点维护区间的范围内
	int mid=(l+r)>>1,x=sum[lc[v]]-sum[lc[u]];
	if(l==r) return l;//找到第kth的数离散化后的下标,直接返回 
	if(k<=x) return query(lc[u],lc[v],l,mid,k);//kth的数在左儿子的区间中 
	//kth的数在右儿子的区间中,因为左儿子中有x个数,kth的数在右儿子中的排名需减去x 
	else return query(rc[u],rc[v],mid+1,r,k-x);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,k;i<=n;i++)
	scanf("%d",&a[i]),b[i]=a[i];
	sort(b+1,b+n+1);
	cnt=unique(b+1,b+n+1)-b-1;
	build(rt[0],1,cnt);//建一棵空树,类似前缀和的s[0]=0 
	for(int i=1;i<=n;i++)
	{
		int p=lower_bound(b+1,b+cnt+1,a[i])-b;//得到a[i]离散化之后的下标 
		rt[i]=update(rt[i-1],1,cnt,p);//返回第i棵线段树的根节点 
	}
	for(int i=1,l,r,k;i<=m;i++)
	{
		scanf("%d%d%d",&l,&r,&k);
		printf("%d\n",b[query(rt[l-1],rt[r],1,cnt,k)]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值