可持久化线段树(主席树)

 我们都知道线段树采用分治的逻辑将区间进行划分,支持单点修改,区间查询。

那么每修改一个叶子节点,只会修改经过它路径的节点,即 logn 个节点。

 

 

运用这个性质,我们现在想要对一个区间进行不同版本的更新,即加入时间这个维度,查询不同时间的该区间。

这时候,主席树就诞生啦!

每次单点修改,我们只需要修改 logn 个点,同时我们还需要保留执之前版本的信息。那么我们所做的不是修改,而是添加,添加 logn 个节点,其中包括这一版本的根节点。

 

 

 到这里,我们明白主席树所耗用的空间是巨大的,假设有n个节点,m次修改,那么所费空间为 O(nlogn+mlogn)。

如此巨大的空间耗费之下,所储存的信息想必也是非常之多的。事实上,主席树的应用十分广泛,例如可以用来求区间第 k 大值,求区间 l,r 中介于 x,y 的值等等。

 

 

代码

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e7+10;
int n,m,t,top,rt,mode,x,y;
int f[N],a[N],root[N];
struct kkk{
    int l,r,val;
}tree[N];
int clone(int node){
    top++;
    tree[top]=tree[node];
    return top;
}
int maketree(int node,int begin,int end){
    node=++top;
    if(begin==end){
        tree[node].val=a[begin];
        return top;
    }
    int mid=begin+end>>1;
    tree[node].l=maketree(tree[node].l,begin,mid);
    tree[node].r=maketree(tree[node].r,mid+1,end);
    return node;
}
int update(int node,int begin,int end,int x,int val){
    node=clone(node);
    if(begin==end) tree[node].val=val;
    else{
        int mid=begin+end>>1;
        if(x<=mid) tree[node].l=update(tree[node].l,begin,mid,x,val);
        else tree[node].r=update(tree[node].r,mid+1,end,x,val);
    }
    return node;
}
int query(int node,int l,int r,int x){
    if(l==r) return tree[node].val;
    else{
        int mid=l+r>>1;
        if(x<=mid) return query(tree[node].l,l,mid,x);
        else return query(tree[node].r,mid+1,r,x);
    }
}
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;++i) cin>>a[i];
    root[0]=maketree(0,1,n);
    for(int i=1;i<=m;++i){
        cin>>rt>>mode>>x;
        if(mode==1){
            cin>>y;
            root[i]=update(root[rt],1,n,x,y);
        }
        else{
            cout<<query(root[rt],1,n,x)<<'\n';
            root[i]=root[rt];
        }
    }
    return 0;
}
复制代码

 

posted @   青阳buleeyes  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示