可持久化线段树
可持久化线段树
可持久化线段树最大的特点是:可以访问历史版本。
考虑一棵普通的线段树,进行单点修改,每次修改会改变
于是每次修改的时候,不修改原来的节点,而是在它旁边新建一个节点,把原来节点的信息(如左右儿子编号、区间和等)复制到新节点上,并对新节点进行修改。
对于查询历史版本,只需记录每一次修改对应的新根节点编号,每次询问从对应的根节点往下查询就可以了。
所以我们只要在记录左右儿子的基础上,保存插入每个数的时候的根节点就可以实现持久化了。
空间 N<<5
主席树
主席树全称是可持久化权值线段树,主要用来求区间第
小
主要思想是每个位置都维护一个线段树,线段树的节点是值的范围,然后第
利用前缀和的思想,如果需要得到
il void insert(int &rt,cs int l,cs int r,cs int k){
t[++id]=t[rt],rt=id,t[rt].sum++;
if(l>=r) return;
int mid=(l+r)>>1;
if(k<=mid) insert(t[rt].ls,l,mid,k);
else insert(t[rt].rs,mid+1,r,k);
return;
}
il int ask(int ql,int qr,int l,int r,int k){
if(l==r) return l;
int mid=(l+r)>>1,lsz=t[t[qr].ls].sum-t[t[ql].ls].sum;
if(lsz>=k) return ask(t[ql].ls,t[qr].ls,l,mid,k);
else return ask(t[ql].rs,t[qr].rs,mid+1,r,k-lsz);
}
code
#include<bits/stdc++.h>
#define il inline
#define cs const
#define ri register
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c=='-'),c=getchar();
while(isdigit(c))x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar('-');
if(x>=10) wt(x/10);
return putchar(x%10+48),void();
}
} using namespace Q;
cs int N=2e5+5,inf=0x3f3f3f3f;
int n,m,rot[N],arr[N],b[N];
struct qaq{
int num,id;
bool operator<(cs qaq o)cs{
return num<o.num;
}
}a[N];
namespace Tree{
int id;
struct qwq{
int ls,rs,sum;
}t[N<<5];
il void insert(int &rt,cs int l,cs int r,cs int k){
t[++id]=t[rt],rt=id,t[rt].sum++;
if(l>=r) return;
int mid=(l+r)>>1;
if(k<=mid) insert(t[rt].ls,l,mid,k);
else insert(t[rt].rs,mid+1,r,k);
return;
}
il int ask(int ql,int qr,int l,int r,int k){
if(l==r) return l;
int mid=(l+r)>>1,lsz=t[t[qr].ls].sum-t[t[ql].ls].sum;
if(lsz>=k) return ask(t[ql].ls,t[qr].ls,l,mid,k);
else return ask(t[ql].rs,t[qr].rs,mid+1,r,k-lsz);
}
} using namespace Tree;
signed main(){
n=rd(),m=rd();
for(ri int i=1;i<=n;++i) a[i]={rd(),i};
sort(a+1,a+1+n);
int len=0;a[0].num=inf;
for(ri int i=1;i<=n;++i){
if(a[i].num!=a[i-1].num){
arr[++len]=a[i].num;
}
b[a[i].id]=len;
}
for(ri int i=1;i<=n;++i){
rot[i]=rot[i-1];
insert(rot[i],1,len,b[i]);
}
for(ri int i=1,l,r,k;i<=m;++i){
l=rd(),r=rd(),k=rd();
wt(arr[ask(rot[l-1],rot[r],1,len,k)]);
putchar('\n');
}
return 0;
}
I went to the woods because I wanted to live deliberately, I wanted to live deep and suck out all the marrow of life, and not when I had come to die, discover that I had not live.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!