可持久化线段树(主席树)及可持久化数组

定义:可以访问历史版本的线段树为可持久化线段树

B站讲解视频:【AgOHの数据结构】主席树

可持久化线段树之所以可以访问历史版本,是因为宏观上看,它为每个版本维护了一棵树。当然,如果真的对每个版本建一颗树,时间空间复杂度都hold不住。所以建立i版本的树时,如果某颗子树相对于i-1版本没有变化,就可以直接使其父亲对应的指针指向i-1版本的这颗子树。

主席树更多的用于单点更新问题,可以为每一次更新后的版本建立一棵树,递归更新的过程中,先令当前节点等于上一个版本的节点,如果某个子树要更新,则新开一个空间存放更新的值。

洛谷模板题

P3834 【模板】可持久化线段树 2(主席树)

题目大意: 给一个长度为n的数组,m次询问一个子区间的第K大。 n ≤ 2 e 5 , m ≤ 2 e 5 n \leq 2e5,m \leq 2e5 n2e5,m2e5
分析: 如果是一次询问整个数组的第K大,可以直接排序也可以通过借鉴快排达到平均 O ( n ) O(n) O(n)的复杂度。
如果有一颗权值线段树,每个节点维护权值在[l, r]范围内的数的个数,那么求[1, n]的第K大,可以通过递归求,如果左子树的数的个数为x, x大于等于K,递归查询左子树第K大,如果x小于等于K,递归查询右子树第K-x大。
为数组的每个前缀建立一颗权值线段树,查询[L, R]区间第K大时, 就可以通过树L-1, 树R结合起来查询第K大,在[l, mid]的数的个数即为R树对应个数减去L-1树对应个数。
AC代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 200000 + 10;
struct node
{
   
	int l, r, cnt;
	node()
	{
   
		l = r = cnt = 0;
	}
}nodes[maxn * 40];
//如果权值线段树某个节点的cnt为0,直接指向nodes[0],节约空间
//每次update新建logn个节点,注意nodes开够
int usecnt = 0;
int root[maxn];//各个版本的根节点

void update(int l, int r, int &rt, int pre, int v)
{
   
	rt = ++usecnt;//分配新节点
	nodes[rt] = nodes[pre];//赋值
	nodes[rt].cnt++;//加入了一个新的数
	if (l == r)return;
	int mid = (l + r) >> 1;
	//更新左边or右边,未更新的维持指向旧版本节点
	if (v <= mid)update(l, mid, nodes[rt].l, nodes[pre].l, v);
	else update(mid + 1, r, nodes[rt].r, nodes[pre].r, v);
}

int query(int l, int r, int k, int Ltree, int Rtree)
{
   
	if (l == r)return l;
	int mid = (l + r) >> 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值