• 主席树模板


    应用场景

    静态: 查询区间第K大

    动态: 带修改的查询区间第K大

    静态

    P3834【模板】可持久化线段树 1(主席树)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define clr(a, x) memset(a, x, sizeof(a))
     4 #define rep(i,a,n) for(int i=a;i<=n;i++)
     5 #define pre(i,a,n) for(int i=a;i>=n;i--)
     6 #define ll long long
     7 const double eps = 1e-6;
     8 const int INF = 0x3f3f3f3f;
     9 const int mod = 1e9 + 7;
    10 const int N = 2e5+20;
    11 int a[N],b[N],T[N],L[N*20],R[N*20],sum[N*20];
    12 int tot = 0,n,q,x,y,z,m;
    13 
    14 int Build(int l,int r)
    15 {
    16     int rt = ++tot;
    17     int mid = (l+r)>>1;
    18     if(l < r)
    19     {
    20         L[rt] = Build(l,mid);
    21         R[rt] = Build(mid+1,r);
    22     }
    23     return rt;
    24 }
    25 
    26 int update(int pre,int l,int r,int x)
    27 {
    28     int rt = ++tot;
    29     int mid = (l+r)>>1;
    30     L[rt] = L[pre]; R[rt] = R[pre]; sum[rt] = sum[pre]+1;
    31     if(l < r)
    32     {
    33         if(x <= mid)
    34             L[rt] = update(L[pre],l,mid,x);
    35         else 
    36             R[rt] = update(R[pre],mid+1,r,x);
    37     }
    38     return rt;
    39 }
    40 
    41 int query(int u,int v,int l,int r,int k)
    42 {
    43     if(l == r)
    44         return l;
    45     int mid = (l+r)>>1;
    46     int x = sum[L[v]]-sum[L[u]];
    47     if(x >= k)
    48         return query(L[u],L[v],l,mid,k);
    49     else 
    50         return query(R[u],R[v],mid+1,r,k-x);
    51 }
    52 
    53 int main()
    54 {
    55     tot = 0;
    56     clr(T,0);   clr(sum,0); clr(L,0);   clr(R,0);   clr(a,0);   clr(b,0);
    57     scanf("%d %d",&n,&q);
    58     rep(i,1,n)
    59     {
    60         scanf("%d",&a[i]);
    61         b[i] = a[i];
    62     }   
    63     sort(b+1,b+1+n);
    64     m = unique(b+1,b+1+n)-b-1;
    65     T[0] = Build(1,m);
    66     rep(i,1,n)
    67     {
    68         a[i] = lower_bound(b+1,b+1+m,a[i])-b;
    69         T[i] = update(T[i-1],1,m,a[i]);
    70     }
    71     rep(i,1,q)
    72     {
    73         scanf("%d %d %d",&x,&y,&z);
    74         int p = query(T[x-1],T[y],1,m,z);
    75         printf("%d
    ",b[p]);
    76     }
    77     return 0;
    78 }

    动态

    P2617 Dynamic Rankings

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 #define clr(a, x) memset(a, x, sizeof(a))
      4 #define rep(i,a,n) for(int i=a;i<=n;i++)
      5 #define pre(i,a,n) for(int i=n;i>=a;i--)
      6 #define ll long long
      7 #define lowbit(a) a&(-a)
      8 const int N = 200050;
      9 
     10 int cnt,siz,dot,idx;
     11 // 内存分配的下标,不同数值点的个数,总共的点数,修改操作的下标
     12 int root[N],cpy[N],data[N];
     13 // 静态主席树的根节点,离散化后的数据,原始数据
     14 int vir[N],use[N];
     15 // 树状数组的节点,计算前缀和时向前走的节点
     16 
     17 // 因为主席树必须离线,所以将指令存下来
     18 struct order
     19 {
     20     bool typ;   // biaoji查询还是修改
     21     int from,to,k;
     22 }command[N];
     23 
     24 struct node
     25 {int son[2],sum;}tree[N*250];
     26 // 内存一定要开的足够大,因为在这里静态主席树和树状数组共用这个数组内的点
     27 
     28 int build(int l,int r)   // 建立空树 类似线段树
     29 {
     30     int now = cnt++;
     31     tree[cnt].sum = 0;
     32     if(l != r)
     33     {
     34         int mid = (l+r)>>1;
     35         tree[now].son[0] = build(l,mid);
     36         tree[now].son[1] = build(mid+1,r);
     37     }
     38     return now;
     39 }
     40 
     41 int updata(int last,int pos,int val)   // 更新虚拟节点或者插入静态主席树的函数
     42 // 为了方便删除,传入val代表修改的量
     43 {
     44     int now = cnt++,tmp = now,mid;
     45     int l = 0,r = siz-1;   // 保存的是离散化后的对应的值的编号
     46     tree[now].sum = tree[last].sum+val;
     47     while(l < r)
     48     {
     49         mid = (l+r)>>1;
     50         if(pos <= mid)   // 待插入节点在左子树
     51         {
     52             tree[now].son[1] = tree[last].son[1];
     53             // 那么当前节点的右子树节点和之前的那棵权值线段树共用节点
     54             tree[now].son[0] = cnt++;   // 向左新开一个节点
     55             now  = tree[now].son[0];
     56             last = tree[last].son[0];
     57             r = mid;
     58         }
     59         else            // 待插入节点在右子树 
     60         {
     61             tree[now].son[0] = tree[last].son[0];
     62             tree[now].son[1] = cnt++;
     63             now  = tree[now].son[1];
     64             last = tree[last].son[1];
     65             l = mid+1;
     66         }
     67         tree[now].sum = tree[last].sum+val;
     68     }
     69     return tmp;
     70 }
     71 
     72 void add(int now,int pos,int val)
     73 {
     74     while(now <= dot)
     75     {
     76         vir[now] = updata(vir[now],pos,val);
     77         now += lowbit(now);
     78     }
     79 }
     80 
     81 int getsum(int now)   // 查询当前点更改值的左子树的大小
     82 {
     83     int ret = 0;
     84     while(now > 0)
     85     {
     86         ret += tree[tree[use[now]].son[0]].sum;
     87         now -= lowbit(now);
     88     }
     89     return ret;
     90 }
     91 
     92 int query(int l,int r,int kth)
     93 {
     94     int left_root  = root[l-1];  // 静态主席树的两个相减的根节点
     95     int right_root = root[r];
     96     int lef = 0,rig = siz-1;     // 查询时左右范围
     97     for(int i = l-1;i;i -= lowbit(i))  use[i] = vir[i];
     98     // 初始化更改值的路径
     99     for(int i = r;i;i -= lowbit(i))    use[i] = vir[i];
    100     while(lef < rig)
    101     {
    102         int mid = (lef+rig)>>1;
    103         int now_sum = getsum(r)-getsum(l-1)+tree[tree[right_root].son[0]].sum-tree[tree[left_root].son[0]].sum;
    104         // 查询当前点的左儿子是否满足达到了k个
    105         // 在静态主席树和树状数组上一起算
    106         if(now_sum >= kth)   // 达到了
    107         {
    108             rig = mid;
    109             for(int i = l-1;i;i -= lowbit(i))   use[i] = tree[use[i]].son[0];
    110             // 将查询范围缩小至左子树内
    111             for(int i = r;i;i -= lowbit(i))     use[i] = tree[use[i]].son[0];
    112             left_root  = tree[left_root].son[0];   // 同时静态主席树也要如此
    113             right_root = tree[right_root].son[0];
    114         }
    115         else   // 没达到就在右子树范围内继续查找 
    116         {
    117             lef = mid+1;
    118             kth -= now_sum;   // 因为有了左子树的一部分点,所以要减去
    119             for(int i = l-1;i;i -= lowbit(i))   use[i] = tree[use[i]].son[1];
    120             for(int i = r;i;i -= lowbit(i))     use[i] = tree[use[i]].son[1];
    121             left_root  = tree[left_root].son[1];
    122             right_root = tree[right_root].son[1];
    123         }
    124     }
    125     return lef;   // 返回是第几个离散出来的数据
    126 }
    127 
    128 int id(int now)
    129 {
    130     return lower_bound(cpy,cpy+siz,now)-cpy;
    131 }
    132 
    133 int main()
    134 {
    135     int num;
    136     scanf("%d %d",&dot,&num);
    137     idx = dot;
    138     for(int i = 1;i <= dot;i++)
    139     {
    140         scanf("%d",&data[i]);
    141         cpy[i-1] = data[i];   // cpy从0开始存方便unique和sort
    142     }
    143     char c[10];
    144     for(int i = 1;i <= num;i++)
    145     {
    146         scanf("%s",c);
    147         if(c[0] == 'Q')
    148         {
    149             command[i].typ = false;
    150             scanf("%d %d %d",&command[i].from,&command[i].to,&command[i].k);
    151         }
    152         else 
    153         {
    154             command[i].typ = true;
    155             scanf("%d %d",&command[i].from,&command[i].k);
    156             cpy[idx++] = command[i].k;   // 如果是修改的话存入cpy中
    157         }
    158     }
    159     sort(cpy,cpy+idx);
    160     siz = unique(cpy,cpy+idx)-cpy;
    161     root[0] = build(0,siz-1);    // 建立空静态主席树
    162     for(int i = 1;i <= dot;i++)
    163         root[i] = updata(root[i-1],id(data[i]),1);   // 建立满的静态主席树
    164     for(int i = 1;i <= dot;++i)
    165         vir[i] = root[0];         // 初始化树状数组
    166     for(int i = 1;i <= num;i++)   // 处理指令
    167     {
    168         if(!command[i].typ)
    169           printf("%d
    ",cpy[query(command[i].from,command[i].to,command[i].k)]);
    170         else 
    171         {
    172             add(command[i].from,id(data[command[i].from]),-1);
    173             add(command[i].from,id(command[i].k),1);
    174             data[command[i].from] = command[i].k;   // 将原数据修改至新数据
    175         }
    176     }
    177     return 0;
    178 }
  • 相关阅读:
    如何安装一个高可用K3s集群?
    如何设置一个生产级别的高可用etcd集群
    从架构到部署,全面了解K3s
    这应该是最适合国内用户的K3s HA方案
    在K3s上使用Kong网关插件,开启K3s的无限可能!
    AngularJS 遗留项目的升级改造之路(一)
    Rancher首席架构师解读Fleet:它何以管理百万集群?
    资深首席架构师预测:2021年云计算的8个首要趋势
    简单4步,利用Prometheus Operator实现自定义指标监控
    当年,我的架构师之路差点完蛋,幸亏了它
  • 原文地址:https://www.cnblogs.com/duny31030/p/14304988.html
Copyright © 2020-2023  润新知