zoukankan      html  css  js  c++  java
  • 【模板】主席树的学习

    Kth number

    划分树虽然可以做,但是代码不好记。

    看某人blog学习了主席树的简单操作。

    引用某大牛的话来解释一下主席树:

    所谓主席树呢,就是对原来的数列[1..n]的每一个前缀[1..i](1≤i≤n)建立一棵线段树,线段树的每一个节点存某个前缀[1..i]中属于区间[L..R]的数一共有多少个(比如根节点是[1..n],一共i个数,sum[root] = i;根节点的左儿子是[1..(L+R)/2],若不大于(L+R)/2的数有x个,那么sum[root.left] = x)。若要查找[i..j]中第k大数时,设某结点x,那么x.sum[j] - x.sum[i - 1]就是[i..j]中在结点x内的数字总数。而对每一个前缀都建一棵树,会MLE,观察到每个[1..i]和[1..i-1]只有一条路是不一样的,那么其他的结点只要用回前一棵树的结点即可,时空复杂度为O(nlogn)。

    ——具体看代码(有详细注释)

     1 #include <cstdio>
     2 #include <algorithm>
     3 #define lc son[now][0], l, mid
     4 #define rc son[now][1], mid + 1, r
     5 
     6 using namespace std;
     7 
     8 const int N = 100000 + 5;
     9 
    10 int T, n, q, tot;
    11 int a[N], b[N], son[20 * N][2], sum[20 * N], rt[20 * N];
    12 //主席树第 i 棵树存的是 a[0] - a[i] 的树(前缀和) 
    13 //主席树一个节点 sum 存的是当前线段所包含的数的个数。。晕。 
    14 //rt 是每一棵树的根节点编号
    15 //a 保存原数组,b 保存排序后的数组 
    16 
    17 //注意 & 的使用
    18 inline void build(int &now, int l, int r)
    19 {
    20     now = ++tot;
    21     sum[now] = 0;
    22     if(l == r) return;
    23     int mid = (l + r) >> 1;
    24     build(lc);
    25     build(rc);
    26 }
    27 
    28 inline void update(int &now, int l, int r, int last, int x)
    29 {
    30     now = ++tot;
    31     //继承上个节点的孩子 
    32     son[now][0] = son[last][0];
    33     son[now][1] = son[last][1];
    34     //继承上一个节点的 sum 并加上当前所加入的数的个数(就是1) 
    35     sum[now] = sum[last] + 1; 
    36     if(l == r) return;
    37     int mid = (l + r) >> 1;
    38     if(x <= mid) update(lc, son[now][0], x);
    39     else update(rc, son[now][1], x);
    40 }
    41 
    42 //因为每个节点存的是有多少个数在当前区间
    43 //求区间 [1,3] 即求 rt[3] - rt[0] 内的数
    44 //可通过递归二分解决 
    45 inline int query(int s, int t, int l, int r, int x)
    46 {
    47     if(l == r) return l;
    48     int mid = (l + r) >> 1, cnt = sum[son[t][0]] - sum[son[s][0]];
    49     if(x <= cnt) return query(son[s][0], son[t][0], l, mid, x);
    50     else return query(son[s][1], son[t][1], mid + 1, r, x - cnt);
    51 }
    52 
    53 int main()
    54 {
    55     int i, x, y, z, sz;
    56     scanf("%d", &T);
    57     while(T--)
    58     {
    59         scanf("%d %d", &n, &q);
    60         for(i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
    61         sort(b + 1, b + n + 1);
    62         sz = unique(b + 1, b + n + 1) - (b + 1);//求不同的数一共有几个,即区间大小 
    63         tot = 0;
    64         build(rt[0], 1, sz);
    65         //用每个元素在 b 中的坐标重置 a 数组(离散化) 
    66         for(i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + sz + 1, a[i]) - b;
    67         for(i = 1; i <= n; i++) update(rt[i], 1, sz, rt[i - 1], a[i]);
    68         while(q--)
    69         {
    70             scanf("%d %d %d", &x, &y, &z);
    71             printf("%d
    ", b[query(rt[x - 1], rt[y], 1, sz, z)]);
    72         }
    73     }
    74     return 0;
    75 }
    View Code

     K-th Number

    ——代码

     1 #include <cstdio>
     2 #include <algorithm>
     3 #define debug puts("***********");
     4 
     5 const int MAXN = 100001;
     6 int n, m, cnt;
     7 int b[MAXN], root[MAXN];
     8 struct node
     9 {
    10     int a, rank;
    11 }p[MAXN];
    12 struct pst
    13 {
    14     int sum, ls, rs;
    15 }t[MAXN * 20];
    16 
    17 inline bool cmp(node x, node y)
    18 {
    19     return x.a < y.a;
    20 }
    21 
    22 inline void insert(int x, int &now, int l, int r)
    23 {
    24     t[++cnt] = t[now];
    25     now = cnt;
    26     t[now].sum++;
    27     if(l == r) return;
    28     int mid = (l + r) >> 1;
    29     if(x <= mid) insert(x, t[now].ls, l, mid);
    30     else insert(x, t[now].rs, mid + 1, r);
    31 }
    32 
    33 inline int query(int x, int y, int k, int l, int r)
    34 {
    35     if(l == r) return l;
    36     int ans = t[t[y].ls].sum - t[t[x].ls].sum, mid = (l + r) >> 1;;
    37     if(k <= ans) return query(t[x].ls, t[y].ls, k, l, mid);
    38     else return query(t[x].rs, t[y].rs, k - ans, mid + 1, r);
    39 }
    40 
    41 int main()
    42 {
    43     int i, x, y, z;    
    44     scanf("%d %d", &n, &m);
    45 
    46     //没有重复元素的离散化 
    47     for(i = 1; i <= n; i++) scanf("%d", &p[i].a), p[i].rank = i;
    48     std::sort(p + 1, p + n + 1, cmp);
    49     for(i = 1; i <= n; i++) b[p[i].rank] = i;
    50     
    51     for(i = 1; i <= n; i++)
    52     {
    53         root[i] = root[i - 1];
    54         insert(b[i], root[i], 1, n);
    55     }
    56     for(i = 1; i <= m; i++)
    57     {
    58         scanf("%d %d %d", &x, &y, &z);
    59         printf("%d
    ", p[query(root[x - 1], root[y], z, 1, n)].a);
    60     }
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    ABAP接口用法
    监听textarea数值变化
    The first step in solving any problem is recognizing there is one.
    Wrinkles should merely indicate where smiles have been.
    God made relatives.Thank God we can choose our friends.
    Home is where your heart is
    ABAP跳转屏幕
    Python 工具包 werkzeug 初探
    atom通过remote ftp同步本地文件到远程主机的方法
    Mongodb学习笔记一
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6749306.html
Copyright © 2011-2022 走看看