可持久化线段树学习笔记


前言

这和可持久化Trie树怎么这么像呢?
“疯狂动物城”的码量太大了吧(oj过了但洛谷才20pts 强烈建议加强数据 )
空间计算量可真“小”
打得不好,让各位巨佬见笑了
既造福后人,也是给自己提供一些启发和…


是什么

可持久化线段树是一种支持历史版本查询的数据结构,它可以在每一次修改后生成新的版本,同时保留旧版本的信息。在许多需要追踪历史版本的问题中,可持久化线段树都可以提供高效的解决方案。

可持久化线段树和普通线段树的本质区别在于,它每次修改时都会生成一个新的版本。因此,我们需要额外的空间来存储每一个版本中线段树的节点信息。当需要查询一个历史版本时,我们可以通过遍历该版本的线段树节点来得到相应的结果。

可持久化线段树的时间复杂度与普通线段树相同,均为 O ( log ⁡ n ) O(\log n) O(logn)。在实际应用中,我们可以通过对可持久化线段树的节点进行优化,来进一步提高查询和修改的效率。


实现

(无说明则拿可持久化权值线段树为例)

关于定义

struct Node{
	int lson,rson,cnt;
	//......其他属性
}

自认为打得通俗易懂

单点修改

void add(int left,int right,int val,int lst,int &now){
	a[(now=++sum)]=a[lst];//
	a[now].cnt++;
	if(left==right)return;
	int mid=(left+right)/2;
	if(val<=mid)add(left,mid,val,a[lst].lson,a[now].lson);
	else add(mid+1,right,val,a[lst].rson,a[now].rson);
}

其中now为当前版本的点的编号,lst为上一版本的点的编号

区间修改

以“疯狂动物城”为例

void change(int left,int right,int L,int R,long long num,int lst,int &now){
	if(left>R||right<L)return;
	a[now=++sum]=a[lst];
	if(left>=L&&right<=R){
		a[now].tag+=num;
		a[now].num.add(num);
		return;
	}if(left==right)return;
	int mid=(left+right)>>1;
	if(L<=mid)change(left,mid,L,R,num,a[lst].lson,a[now].lson);
	if(mid+1<=R)change(mid+1,right,L,R,num,a[lst].rson,a[now].rson);
	a[now].num=a[a[now].lson].num+a[a[now].rson].num;//左右子树合并
	a[now].num.add(a[now].tag);
}

其中tag为懒标记

单点查询

int find(int aa,int bb,int left,int right,int val){
	if(left==right)return a[aa].cnt-a[bb].cnt;
	int mid=(left+right)/2;
	if(val<=mid)return find(a[aa].lson,a[bb].lson,left,mid,val)+a[a[aa].rson].cnt-a[a[bb].rson].cnt;
	return find(a[aa].rson,a[bb].rson,mid+1,right,val);
}

区间查询

以“疯狂动物城”为例

void ask_ans(int left,int right,int L,int R,int x,long long ss){
	if(left>right||!x)return;
	if(left>=L&&right<=R){
		tt=a[x].num;
		tt.add(ss);
		ans=ans+tt;
		return;
	}
	int mid=(left+right)>>1;
	if(L<=mid)ask_ans(left,mid,L,R,a[x].lson,(ss+a[x].tag)%mod);
	if(mid+1<=R)ask_ans(mid+1,right,L,R,a[x].rson,(ss+a[x].tag)%mod);
}

其中ss为父节点及其根节点传下的tag之和,ans统计答案


总结

可持久化数据结构的根本思路就是不断开点,然后动态维护它以及它的历史版本
注意好空间,不要吝啬!!!血的教训!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值