首页 > 其他分享 >可持久化线段树

可持久化线段树

时间:2022-09-06 21:56:26浏览次数:95  
标签:持久 int 线段 u1 MAXN 区间 Size

现想现写的,没有借鉴别人的任何东西。

可持久化线段树1

考虑不会变得太多,每次该值操作只会改变一个位置的值,其它位置是可以继承的。如果用数组,那就是下标继承。如果把数组分成 \(2\) 半,那改一个值,就一半继承,另一半重新赋值。而用线段树,就可以做到区间继承 \(\log\) 的时间复杂度。

所以就是:当前区间分成 \(2\) 半,一半直接继承原来的,另一半继续递归下去,又可以分。

查询跟普通线段树一样。

时间复杂度 \(O(n\log_{2}n)\)。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e7+4e6;
int tr[MAXN],ls[MAXN],rs[MAXN],tot;
int Root[MAXN];
void Add(int &u1,int u2,int l,int r,int id,int Val)
{
	if(!u1)
	{
		u1=++tot;
	}
	if(l==r)
	{
		tr[u1]=Val;
		return;
	}
	int Mid=l+r>>1;
	if(id<=Mid)
	{
		rs[u1]=rs[u2];
		Add(ls[u1],ls[u2],l,Mid,id,Val);
	}
	else
	{
		ls[u1]=ls[u2];
		Add(rs[u1],rs[u2],Mid+1,r,id,Val);
	}
}
int Query(int u,int l,int r,int x)
{
	if(l==r)
	{
		return tr[u];
	}
	int Mid=l+r>>1;
	if(x<=Mid)
	return Query(ls[u],l,Mid,x);
	else
	return Query(rs[u],Mid+1,r,x);
}
int N,Q;
int a[MAXN];
void Build(int &u,int l,int r)
{
	if(!u)
	{
		u=++tot;
	}
	if(l==r)
	{
		tr[u]=a[l];
		return;
	}
	int Mid=l+r>>1;
	Build(ls[u],l,Mid);
	Build(rs[u],Mid+1,r);
}
int main()
{
	scanf("%d%d",&N,&Q);
	for(int i=1;i<=N;i++)
	{
		scanf("%d",&a[i]);
	}
	Build(Root[0],1,N);
	for(int i=1;i<=Q;i++)
	{
		int v,op,Loc,Value;
		scanf("%d%d%d",&v,&op,&Loc);
		if(op==1)
		{
			scanf("%d",&Value);
			Add(Root[i],Root[v],1,N,Loc,Value);
		}
		if(op==2)
		{
			Root[i]=Root[v];
			printf("%d\n",Query(Root[v],1,N,Loc));
		}
	}
}

可持久化线段树2

离散化,建权值线段树。对于第 \(i\) 个值,才建一棵线段树包含 \(a_1\) 至 \(a_i\) 的值,这可以持久化。

记录每个值域线段树每个值域区间的 Size 表示这里面有多少个有被用的叶子,上述操作相当于每次新建一棵线段树,新将一个叶子赋值为被用过。

然后查询区间 \([L,R]\) 第 \(k\) 大,对于当前递归到的区间,如果左区间的 \(Size_R-Size_{L-1}\) 比 \(k\) 小,那就说明左区间的数不够 \(k\) 个,第 \(k\) 大一定为右区间的第 \(k-(Size_R-Size_{L-1})\) 大,再递归下去。反之就不减,递归到左区间。

最后一定会出结果,除非这个区间一共都没有 \(k\) 个值。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN=5e6+50;
int N,Q;
int a[MAXN];
vector<int>lsh;
int Size[MAXN];
int ls[MAXN],rs[MAXN];
int tot;
int Root[MAXN];
void Add(int &u1,int u2,int l,int r,int Val)
{
	if(!u1)
	u1=++tot;
	if(l==r)
	{
		Size[u1]=Size[u2]+1;
		return;
	}
	int Mid=l+r>>1;
	if(Val<=Mid)
	{
		rs[u1]=rs[u2];
		Add(ls[u1],ls[u2],l,Mid,Val);
	}
	else
	{
		ls[u1]=ls[u2];
		Add(rs[u1],rs[u2],Mid+1,r,Val);
	}
	Size[u1]=Size[ls[u1]]+Size[rs[u1]];
}
int Query(int u1,int u2,int l,int r,int k)
{
	if(l==r)
	{
		return l;
	}
	int Mid=l+r>>1;
	if(k<=Size[ls[u1]]-Size[ls[u2]])
	{
		return Query(ls[u1],ls[u2],l,Mid,k);
	}
	else
	{
		k-=(Size[ls[u1]]-Size[ls[u2]]);
		return Query(rs[u1],rs[u2],Mid+1,r,k);
	}
}
int Back[MAXN];
int main()
{
	scanf("%d%d",&N,&Q);
	for(int i=1;i<=N;i++)
	{
		scanf("%d",&a[i]);
		lsh.push_back(a[i]);
	}
	sort(lsh.begin(),lsh.end());
	int Cnt=unique(lsh.begin(),lsh.end())-lsh.begin();
	for(int i=1;i<=N;i++)
	{
		a[i]=lower_bound(lsh.begin(),lsh.begin()+Cnt,a[i])-lsh.begin()+1;
		Back[a[i]]=lsh[a[i]-1];
	}
	for(int i=1;i<=N;i++)
	{
		Add(Root[i],Root[i-1],1,Cnt,a[i]);
	}
	while(Q--)
	{
		int l,r,k;
		scanf("%d%d%d",&l,&r,&k);
		printf("%d\n",Back[Query(Root[r],Root[l-1],1,Cnt,k)]);
	}
}

标签:持久,int,线段,u1,MAXN,区间,Size
From: https://www.cnblogs.com/0htoAi/p/16663455.html

相关文章

  • Slayers Come (区间覆盖种类数(dp+线段树)+ st表+二分,或者线段树) (2022杭电多校2)
    题目;给你一个长度为n的数组,每个位置上有一个野怪,野怪的攻击力和血量已知,你有m个技能,每个技能有三个值,一是可以击败的怪物,且怪物死后会攻击与它相邻的怪对于左边的怪伤害......
  • Static Query on Tree (述链剖分+线段树)(2022杭电多校)
    题意:给定一棵树,nn 个结点。根为 11,所有的结点只能走向其父亲结点。有 qq 次询问,每次询问给出 33 个结点集合 A,B,CA,B,C。问树上有多少点满足如下条件:该点可以......
  • DOS Card (线段树)(hud杭电多校)
    题目:对序列 a,回答 q 次询问:给定长度至少为 4 的区间 [L,R],在区间内选择 1对 (ai,aj)(L≤i<j≤R)可以获取分数 (ai+aj)(ai−aj) ,计算选择 2 对可以获取的最......
  • 【luogu CF633H】Fibonacci-ish II(莫队)(线段树)(矩阵乘法)
    Fibonacci-ishII题目链接:luoguCF633H题目大意给你一个序列,每次问你一个区间,把里面的数拿出来去重排序,第i个位置乘上斐波那契数列第i项之后所有数的和。思路这题......
  • 线段树
    #include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=100001;llsum[N*4];lltag[N*4];inta[N];voidpushdown(intx,intl_len,......
  • CF446C(线段树+斐波那契)
    CF446C(线段树+斐波那契数列)CF链接洛谷链接题目大意:区间加斐波那契数列,区间求和分析:一眼鉴定为线段树难点在于如何打标记,合并和传递标记对于斐波那契数列有几个性......
  • redis持久化部署
    redis持久化部署Redis简介软件说明Redis是一款开源的,ANSIC语言编写的,高级键值(key-value)缓存和支持永久存储NoSQL数据库产品。Redis采用内存(In-Memory)数据集(DataS......
  • Android学习笔记八(JAVA):数据库与Room持久性库,菜单栏,数据绑定
    本篇笔记实现如下所示的功能。在NoteListFragment页面增加了菜单栏,菜单栏中有NewNote选项,点击它跳转到新建Note页面。输入TITLE和CONTENT后,点击CREATE按钮,会在数据库中添......
  • 浅淡线段树合并
    线段树,是信息学比赛中一种强有力的数据结构;动态开点,让线段树在数据范围上挣脱了束缚;线段树合并,让树上问题获得了升华。前言线段树合并的基础——动态开点线段树在初学......
  • 08. Prometheus - 查询持久化与服务发现
    查询持久化前面编写的PromQL都是一次性的,下次使用需要重写编写。为了方便以后拿来即用,Prometheus提供了在配置文件中的持久化方案。cd/ezops/service/prometheus/con......