算法学习笔记:主席树

主席树介绍:

主席树又被称为持久化线段树,也就是某一时刻对线段树的操作可以被保存下来,后面可以随时在以前的版本上进行查询和修改,这种持久化思想不仅可以用于线段树,还可以用于并查集和平衡树等等。

主席树原理:

需要查询以前的某一个版本,那么我们肯定需要对每一次修改都保存下来。但是如果将整棵树都保存下来,需要的时间和空间成本都太高。所以我们选择保存发生变化的节点:

当修改操作新衍生出一个版本,只需要新建根节点和发生变化的节点即可。

这个时候我们只需要再建立一个数组,保存每个版本的根节点,就可以实现在任意版本上进行查询和修改。

主席树实现:

建树:

struct Node{
    int l;
    int r;
    int val;
}node[N];

int tot=0;
int root[N];
int root_sum=0;

int a[N];    //用于保存初始建树的值


//递归建树,返回根节点索引
int build(int l,int r){
    if(l==r){
        tot++;
        node[tot].l = node[tot].r = 0;
        node[tot].val = a[l];
        return tot;
    }
    int now = ++tot;
    int mid = (l+r)>>1;
    node[now].l = build(l,mid);        //递归建立左子树
    node[now].r = build(mid+1,r);      //递归建立右子树
    node[now].val = node[node[now].l].val + node[node[now].r].val;
    return now;
}

修改:

//在p版本的基础上修改主席树k号元素为e,并衍生出一个新版本
int change(int p,int l,int r,int k,int e){
    if(l==r){
        tot++;
        node[tot].l = node[tot].r = 0;
        node[tot].val = e;
        return tot;
    }
    int now = ++tot;
    int mid = (l+r)>>1;

    node[now].l = node[p].l;        //先复制上一个版本的子节点
    node[now].r = node[p].r;
    
    //只修改变化的子节点
    if(k<=mid) node[now].l = change(node[p].l,l,mid,k,e);
    else node[now].r = change(node[p].r,mid+1,r,k,e);

    node[now].val = node[node[now].l].val + node[node[now].r].val;
    return now;
}

查询:

//查询以p为根节点版本的k号元素
int find(int p,int l,int r,int k){
    if(l==r) return node[p].val;
    int mid = (l+r)>>1;
    if(k<=mid) return find(node[p].l,l,mid,k);
    else return find(node[p].r,mid+1,r,k);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值