首页 > 其他分享 >主席树学习笔记

主席树学习笔记

时间:2023-04-12 15:24:02浏览次数:45  
标签:pre val rs int mid 笔记 学习 ls 主席

主席树,又名可持久化线段树,可以访问多个历史版本的树上存的信息。

图及其他来源于此:https://www.cnblogs.com/hyfhaha/p/10678275.html

基本思想

用到的基本思想就是对于每一个修改版本的树,只新建修改后的节点,如果是每一个版本新开一个线段树的话空间一定不够。

image

这是普通的线段树单点修改。

image

这是主席树的单点修改。

几个月前我被这个东西劝退了,但现在来看挺好理解的,无非就是把修改的点从下到上涉及到的值有变化的点新开一个点,然后对于一些有没有变化的点,直接和修改后的连起来即可,根据根节点的不同可以判断是那个版本的点。

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

这个题目就是单点修改单点查询,可以配合代码以及注释理解一下。

#include<bits/stdc++.h>
#define N 1000010
using namespace std;
int a[N],n,m,q,rt[N*30];//a存放输入的每一个点的值,rt存放每一个版本的根节点 
int ls[N*30],rs[N*30],val[N*30],cnt;//存放每一个节点的左右儿子,值 
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
inline void build(int &x,int l,int r)//建树 
{
	x=++cnt;//存编号 
	if(l==r){val[x]=a[l];return ;}//如果到了叶子节点就直接赋值退出 
	int mid=(l+r)>>1;//计算mid的值 
	build(ls[x],l,mid);//递归建左子树 
	build(rs[x],mid+1,r);//递归建右子树 
}
inline void ins(int &x,int pre,int l,int r,int q,int v)//在某个版本修改某个值 
{
	x=++cnt;ls[x]=ls[pre];rs[x]=rs[pre];val[x]=val[pre];//复制节点 
	if(l==r){val[x]=v;return ;}//修改当前节点的值 
	int mid=(l+r)>>1;//计算mid的值 
	if(q<=mid)ins(ls[x],ls[pre],l,mid,q,v);//根据版本去修改 
	else ins(rs[x],rs[pre],mid+1,r,q,v);
}
inline int sum(int x,int l,int r,int q)//区间求值 
{
	if(l==r)return val[x];//如果当前点就是要差查的值就直接返回 
	int mid=(l+r)>>1;//计算mid的值 
	if(q<=mid)return sum(ls[x],l,mid,q);//按编号查询 
	else return sum(rs[x],mid+1,r,q);
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	build(rt[0],1,n);//建树,初始版本号:0 
	for(int i=1;i<=m;i++)//m次操作,m个新版本 
	{
		int pre=read(),op=read(),x=read();//输入版本号,操作,序号 
		if(op==1){int v=read();ins(rt[i],rt[pre],1,n,x,v);}//操作一,修改值 
		else {cout<<sum(rt[pre],1,n,x)<<endl;rt[i]=rt[pre];}
	}
	return 0;//好习惯 
}

P3834 【模板】可持久化线段树 2

这题我们需要考虑主席树

首先我们可以想到,我们先从小到大排序离散化一下,然后我们可以一个一个把数插入到主席树上,一共是 \(n\) 个版本,然后第 \(i\) 个版本代表的是前 \(i\) 个数在数列中的排名情况,然后对于 \(l\) 到 \(r\) 之间的点我们可以直接用前缀和思想,用 \(i\) 版本减去 \(i-1\) 版本的树上节点就可以了。

#include<bits/stdc++.h>
#define N 1000100
#define endl '\n'
using namespace std;
int n,m,rt[N],ls[N<<5],rs[N<<5];
int cnt,b[N],a[N],val[N<<5];
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
inline void build(int &x,int l,int r)
{
	x=++cnt;
	if(l==r)return ;
	int mid=(l+r)>>1;
	build(ls[x],l,mid);
	build(rs[x],mid+1,r);
}
inline void add(int &x,int pre,int l,int r,int p)
{
	x=++cnt;ls[x]=ls[pre];rs[x]=rs[pre];val[x]=val[pre]+1;
	if(l==r)return ;
	int mid=(l+r)>>1;
	if(p<=mid)add(ls[x],ls[pre],l,mid,p);
	else add(rs[x],rs[pre],mid+1,r,p);
}
inline int ask(int u,int v,int l,int r,int k)
{
	if(l==r)return b[l];
	int mid=(l+r)>>1;
	int num=val[ls[v]]-val[ls[u]];
	if(num>=k)return ask(ls[u],ls[v],l,mid,k);
	else return ask(rs[u],rs[v],mid+1,r,k-num);
}
signed main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)b[i]=a[i]=read();
	sort(b+1,b+n+1);
	int len=unique(b+1,b+n+1)-b-1;
	build(rt[0],1,len);
	for(int i=1;i<=n;i++)
	{
		int x=lower_bound(b+1,b+len+1,a[i])-b;
		add(rt[i],rt[i-1],1,len,x);
	}
	for(int i=1;i<=m;i++)
	{
		int l=read(),r=read(),x=read();
		cout<<ask(rt[l-1],rt[r],1,len,x)<<endl;
	}
	return 0;
}

标签:pre,val,rs,int,mid,笔记,学习,ls,主席
From: https://www.cnblogs.com/Multitree/p/17299441.html

相关文章

  • 关于中育云笔记的本次更新(1.9.21)
    前言Before其实贴吧上传文件的代码我是第一批知道的人,我一开始也不会用,然后去问了开发者后来我就犹豫了一下要不要像之前换头像一样写个详细的教程,但又觉得影响不太好等到那天晚上他写了个恶搞小教程出来后,我就直接跟他说,这样早晚会出事,而且可能会连累到我们现在有点东西他回......
  • 深度学习的优化算法
    目前,深度学习的优化器以反向传播的梯度下降算法为主流。常见的优化器有如下几种:BGDSGDMBGDMomentumRMSPropAdaGradAdam1.批量梯度下降(BatchGradientDescent,BGD)2.随机梯度下降法(StochasticGradientDescent,SGD)3.小批量随机梯度下降(Mini-batchGradientDesc......
  • Gin学习笔记--中间件
    所有的请求都会经过中间件示例代码:packagemainimport("fmt""github.com/gin-gonic/gin""time")funcmain(){engine:=gin.Default()engine.Use(func(context*gin.Context){s:=time.Now()fmt.Print......
  • 正则表达式-笔记
    元字符元字符就是指那些在正则表达式中具有特殊意义的专用字符元字符的分类与记忆技巧我们可以把元字符大致分为这几类:表示单个特殊字符的,表示空白符的,表示某个范围的,表示次数的量词,另外还有表示断言的,我们可以把它理解成边界限定。特殊单字符.任意字符(换行除外)\d任意数......
  • go语言学习-gin框架中间件
    全局中间件所有的请求都经过此中间件//所有请求经过此中间件packagemainimport( "fmt" "time" "github.com/gin-gonic/gin")//定义中间件funcMiddleWare()gin.HandlerFunc{ returnfunc(ctx*gin.Context){ t:=time.Now() fmt.Println("中间件开始执行了......
  • Redis scan等命令的学习与研究
    Redisscan等命令的学习与研究摘要背景跟前几天说的一个问题类似.为了验证自己的设想,所以晚上继续写脚本进行了一轮次的验证.不过上次讨论时,打击好像都没听懂我说的所以这次准备从基础开始讲起.很多好东西在上来量之后可能会变成坏东西scan命令Redis在2.8之后......
  • 动力节点王鹤SpringBoot3笔记——第七章 视图技术Thymeleaf
    7视图技术ThymeleafThymeleaf是一个表现层的模板引擎,一般被使用在Web环境中,它可以处理HTML,XML、JS等文档,简单来说,它可以将JSP作为JavaWeb应用的表现层,有能力展示与处理数据。Thymeleaf可以让表现层的界面节点与程序逻辑被共享,这样的设计,可以让界面设计人员、业......
  • 动力节点SpringBoot3笔记——视图技术Thymeleaf
    7视图技术ThymeleafThymeleaf是一个表现层的模板引擎,一般被使用在Web环境中,它可以处理HTML,XML、JS等文档,简单来说,它可以将JSP作为JavaWeb应用的表现层,有能力展示与处理数据。Thymeleaf可以让表现层的界面节点与程序逻辑被共享,这样的设计,可以让界面设计人员、业......
  • 4.12 三分法学习笔记
    三分的思路和二分有一点像。正好这两天数学在学函数的单调性,所以感觉还不错。但是三分法出题似乎有一定的局限性,所以应用并不广泛,但是还是需要学习一下。P3382【模板】三分法 一个洛谷三分的板子。三分求单峰函数极值。三分适用的情况:有唯一的最大值,满足最大值左侧严格单调递......
  • 机器学习技术在商业领域的应用
    ​ 机器学习是一种人工智能技术,它可以让计算机通过学习数据和模式来自主地进行决策和预测。随着数据量的不断增加和计算能力的提高,机器学习技术在商业领域的应用也越来越广泛。机器学习技术的应用场景机器学习技术可以应用于各个领域,包括金融、零售、医疗、制造等。在金融领域......