【学习】可持久化线段树(主席树)

可持久化数据结构是为了保存这个数据结构的所有历史版本


正文

这是一棵非常好看的线段树

考虑一个问题,现在修改6号节点,同时保留原始信息,怎么做

重构一棵线段树,该修改的就修改,其余信息复制

显然不对因为我们在说可持久化而不是重构

遵从不浪费原则,我们要尽可能多的利用不需要修改的节点

根据线段树的知识,我们知道修改一个点的同时也会影响他的父亲及祖先

所以标星的点是要被修改的

我们把要修改的点重建,保留不需要修改的就变成了介个样子

同时我们还要充分利用旧的线段树,那怎么办呢

直接把他指过去就行了

由于1的左子树和3的右儿子是全部不用修改,所以直接指过去是可以维护的


(不带修)静态查询区间第k大(小)

//
//  main.cpp
//  【模版】可持久化线段树(主席树)
//
//  Created by gengyf on 2019/7/12.
//  Copyright © 2019 yifan Geng. All rights reserved.
//

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define mid (l+r)/2
using namespace std;
const int N = 200010;
int n, q, m, cnt = 0;
int a[N], b[N], T[N];
int sum[N<<5], L[N<<5], R[N<<5];
inline int build(int l, int r){
    int rt = ++ cnt;
    sum[rt] = 0;
    if (l < r){
        L[rt] = build(l, mid);
        R[rt] = build(mid+1, r);
    }
    return rt;
}
inline int update(int pre, int l, int r, int x){
    int rt = ++ cnt;
    L[rt] = L[pre]; R[rt] = R[pre]; sum[rt] = sum[pre]+1;
    if (l < r){
        if (x <= mid) L[rt] = update(L[pre], l, mid, x);
        else R[rt] = update(R[pre], mid+1, r, x);
    }
    return rt;
}
inline int query(int u, int v, int l, int r, int k){
    if (l >= r) return l;
    int x = sum[L[v]] - sum[L[u]];
    if (x >= k) return query(L[u], L[v], l, mid, k);
    else return query(R[u], R[v], mid+1, r, k-x);
}
int main(){
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i ++){
        scanf("%d", &a[i]);
        b[i] = a[i];
    }
    sort(b+1, b+1+n);
    m = unique(b+1, b+1+n)-b-1;
    T[0] = build(1, m);
    for (int i = 1; i <= n; i ++){
        int t = lower_bound(b+1, b+1+m, a[i])-b;
        T[i] = update(T[i-1], 1, m, t);
    }
    while (q --){
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        int t = query(T[x-1], T[y], 1, m, z);
        printf("%d
", b[t]);
    }
    return 0;
}

(带修)动态区间第k大(小)洛谷P2617

  1 //
  2 //  main.cpp
  3 //  【模版】动态区间第k大(树状数组主席树)
  4 //
  5 //  Created by gengyf on 2019/9/1.
  6 //  Copyright © 2019 yifan Geng. All rights reserved.
  7 //
  8 
  9 #include <iostream>
 10 using namespace std;
 11 namespace gengyf{
 12     const int N=5e5+1;
 13     struct ls{
 14         int w,num;
 15     }pp[N<<1];//离散化
 16     struct que{
 17         char ss[3];
 18         int l,r,k;
 19     }q[N];//询问
 20     struct tree{
 21         int w,l,r;
 22     }t[N<<5];
 23     inline bool cmp(ls x,ls y){
 24         return x.w<y.w;
 25     }
 26     int root[N];
 27     int pas[N],now[N],L,R;
 28     int e,ran,sz,a[N<<1],s[N];//离散化数组大小,排名个数,排名数组,原值数组
 29     inline void lisan(){//离散化
 30         sort(pp+1,pp+e+1,cmp);
 31         a[pp[1].num]=ran=1;
 32         s[1]=pp[1].w;
 33         for(int i=2;i<=e;i++){
 34             if(pp[i].w!=pp[i-1].w){
 35                 s[++ran]=pp[i].w;
 36             }
 37             a[pp[i].num]=ran;
 38         }
 39     }
 40     inline int lowbit(int x){
 41         return x&-x;
 42     }
 43     inline void add(int &now,int l,int r,int x){//新建
 44         if(!now){
 45             now=++sz;
 46         }
 47         t[now].w++;
 48         if(l==r){
 49             return ;
 50         }
 51         int mid=(l+r)>>1;
 52         if(x<=mid)add(t[now].l,l,mid,x);
 53         else add(t[now].r,mid+1,r,x);
 54     }
 55     inline void del(int now,int l,int r,int x){//删除
 56         t[now].w--;
 57         if(l==r){
 58             return ;
 59         }
 60         int mid=(l+r)>>1;
 61         if(x<=mid){
 62             del(t[now].l,l,mid,x);
 63             return ;
 64         }
 65         del(t[now].r,mid+1,r,x);
 66     }
 67     inline int kth(int l,int r,int k){//查询
 68         if(l==r){
 69             return l;
 70         }
 71         int sum=0;
 72         for(int i=1;i<=L;i++){
 73             sum-=t[t[pas[i]].l].w;
 74         }
 75         for(int i=1;i<=R;i++){
 76             sum+=t[t[now[i]].l].w;
 77         }
 78         int mid=(l+r)>>1;
 79         if(sum>=k){
 80             for(int i=1;i<=L;i++){
 81                 pas[i]=t[pas[i]].l;
 82             }
 83             for(int i=1;i<=R;i++){
 84                 now[i]=t[now[i]].l;
 85             }
 86             return kth(l,mid,k);
 87         }
 88         for(int i=1;i<=L;i++){
 89             pas[i]=t[pas[i]].r;
 90         }
 91         for(int i=1;i<=R;i++){
 92             now[i]=t[now[i]].r;
 93         }
 94         return kth(mid+1,r,k-sum);
 95     }
 96     int n,m;
 97     int main(){
 98         scanf("%d%d",&n,&m);
 99         for(int i=1;i<=n;i++){
100             scanf("%d",&pp[i].w);
101             pp[i].num=i;
102         }
103         e=n;
104         for(int i=1;i<=m;i++){
105             scanf("%s%d%d",&q[i].ss,&q[i].l,&q[i].r);
106             if(q[i].ss[0]=='Q'){
107                 scanf("%d",&q[i].k);
108             }
109             else {
110                 e++;
111                 pp[e].w=q[i].r;pp[e].num=n+i;
112             }
113         }
114         lisan();
115         for(int i=1;i<=n;i++){
116             int x=i;
117             while(x<=n){
118                 add(root[x],1,ran,a[i]);
119                 x+=lowbit(x);
120             }
121         }
122         for(int i=1;i<=m;i++){
123             if(q[i].ss[0]=='Q'){
124                 L=R=0;
125                 int Now=q[i].l-1;
126                 while(Now){
127                     pas[++L]=root[Now];
128                     Now-=lowbit(Now);
129                 }
130                 Now=q[i].r;
131                 while(Now){
132                     now[++R]=root[Now];
133                     Now-=lowbit(Now);
134                 }
135                 printf("%d
",s[kth(1,ran,q[i].k)]);
136             }
137             else {
138                 int Now=q[i].l;
139                 while(Now<=n){
140                     del(root[Now],1,ran,a[q[i].l]);
141                     Now+=lowbit(Now);
142                 }
143                 Now=q[i].l;
144                 while(Now<=n){
145                     add(root[Now],1,ran,a[i+n]);
146                     Now+=lowbit(Now);
147                 }
148                 a[q[i].l]=a[i+n];
149                 continue;
150             }
151         }
152         return 0;
153     }
154 }
155 int main() {
156     gengyf::main();
157     return 0;
158 }
View Code

ps:目前只放了代码,会补解释的QwQ(咕咕咕~

原文地址:https://www.cnblogs.com/gengyf/p/11178941.html