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


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


    正文

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

    考虑一个问题,现在修改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(咕咕咕~

  • 相关阅读:
    vue 组件之间相互传值 父传子 子传父
    krpano 常用标签
    krpano生成全景图
    github的基本使用
    transform:rotate3d/tranlate3d
    css3水波纹效果
    原型的迷惑
    JS变量作用域
    LeetCode Rotate List
    LeetCode Divide Two Integers
  • 原文地址:https://www.cnblogs.com/gengyf/p/11178941.html
Copyright © 2020-2023  润新知