主席树(萌新,复习用)

主席树是解决查询历史线段树值的问题的数据结构。

由于改变一个点值时,线段树改变不完全,所以利用一个线段树的空间存储一个历史值是很浪费空间的。

那么此时我们只需要建立一个根节点,对未改变的节点连边,对改变的节点新建节点,连边即可。

本算法思路极其简单,主要看代码实现。

void build(int &x,int l,int r)
{
	if(!x)x=++cnt;
	if(l==r)
	{
		f[x].data=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(f[x].ls,l,mid);
	build(f[x].rs,mid+1,r);
}
void update(int &x,int y,int l,int r)
{
	if(!x)x=++cnt;
	if(l==r)
	{
		f[x].data=k;
		return;
	}
	f[x]=f[y];
	int mid=(l+r)>>1;
	if(mid>=nl)update(f[x].ls=0,f[y].ls,l,mid);
	else update(f[x].rs=0,f[y].rs,mid+1,r);
}

应用:解决区间第 k 小问题。

每加入一个数,建立一个版本的线段树,最后利用前缀和求解第 k 小。

void update(int &x,int y,int l,int r)
{
	if(!x)x=++cnt;
	if(l==r)
	{
		f[x].data=f[y].data+1;
		return;
	}
	int mid=(l+r)>>1;
	f[x]=f[y];
	if(mid>=k)update(f[x].ls=0,f[y].ls,l,mid);
	else update(f[x].rs=0,f[y].rs,mid+1,r);
	pushup(x);
}
int search(int x,int y,int l,int r)
{
	if(l==r)return t[l];
	int sum=f[f[y].ls].data-f[f[x].ls].data;
	int mid=(l+r)>>1;
	if(k<=sum)return search(f[x].ls,f[y].ls,l,mid);
	k-=sum;
	return search(f[x].rs,f[y].rs,mid+1,r);
}

思路仍然非常简单,此数据结构注重于应用,所以还要多练习。

P3919 【模板】可持久化线段树 1(可持久化数组)(纯模板)

P3834 【模板】可持久化线段树 2(应用模板)

P3567 [POI2014]KUR-Couriers(简单应用)

P2468 [SDOI2010]粟粟的书架(主席树练习题,合二为一?)

P3302 [SDOI2013] 森林(树上主席树)

P3168 [CQOI2015]任务查询系统(小变式)

P4559 [JSOI2018]列队(大变式)

P2633 Count on a tree(树剖主席树)

P3293 [SCOI2016]美味(主席树变式)

P4618 [SDOI2018]原题识别(主席树树剖)

posted @   Gmt丶Fu9ture  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示