zoukankan      html  css  js  c++  java
  • 【模板】划分树

    K-th Number

    多次询问一个静态区间里的第k大数。怎么搞?

    暴力?(还是别想了)

    多次构建树状数组?(和暴力有啥区别)

    于是一个叫做划分树的东西就登场了。(据说还有个叫归并树的,速度慢一点,就不学了)

    划分树详解

    ——代码

     1 #include <cstdio>
     2 #include <algorithm>
     3 #define N 100001
     4 
     5 using namespace std;
     6 
     7 int n, m;
     8 int c[N];//排序后数组 
     9 int num[20][N], val[20][N];
    10 //一共有20层,每一层元素排放,0层是原数组
    11 //num[i] 表示 i 前面有多少个孩子进入左孩子 
    12 
    13 inline void build(int l, int r, int k)
    14 {
    15     if(l == r) return;
    16     int i, mid = (l + r) / 2, lc = l, rc = mid + 1, isame = mid - l + 1;
    17     //isame 表示有多少个和 c[mid] 相同的数进入左边,先假设全部进入左边 
    18     for(i = l; i <= r; i++)
    19      if(val[k][i] < c[mid])
    20       isame--;//判断,把进入左边的且小于 c[mid] 的减去 
    21     for(i = l; i <= r; i++)
    22     {
    23         num[k][i] = i == l ? 0 : num[k][i - 1];//dp 
    24         if(val[k][i] < c[mid] || (val[k][i] == c[mid] && isame > 0))//进入左孩子
    25         {
    26             val[k + 1][lc++] = val[k][i];
    27             num[k][i]++;
    28             if(val[k][i] == c[mid]) isame--;
    29         }
    30         else val[k + 1][rc++] = val[k][i];//到右孩子 
    31     }
    32     build(l, mid, k + 1);
    33     build(mid + 1, r, k + 1);
    34 }
    35 
    36 inline int query(int l, int r, int k, int ql, int qr, int qk)
    37 {
    38     if(l == r) return val[k][l];//叶子节点即为结果 
    39     int lnum = l == ql ? 0 : num[k][ql - 1], t = num[k][qr] - lnum, mid = (l + r) / 2;//左端点相同? 
    40     //lnum 表示 ql 前面有多少个数进入左孩子,t 表示 ql 和 qr 之间有多少个数进入左孩子 
    41     if(t >= qk) return query(l, mid, k + 1, l + lnum, l + num[k][qr] - 1, qk);
    42     //全在左子树,去左子树搜索 
    43     else
    44     {
    45         //ql - l 表示 ql 前面有多少个数,再减去 lnum 表示有多少个数去了右子树 
    46         int kj = mid + 1 + (ql - l - lnum);
    47         //ql - qr + 1 表示 ql 到 qr 有多少数,减去左边的,剩下的就是去右边的,去右边一个,下标就是kj,所以减一 
    48         return query(mid + 1, r, k + 1, kj, kj + qr - ql + 1 - t - 1, qk - t);
    49     }
    50 }
    51 
    52 int main()
    53 {
    54     int i, x, y, z;
    55     while(~scanf("%d %d", &n, &m))
    56     {
    57         for(i = 1; i <= n; i++) scanf("%d", &val[0][i]), c[i] = val[0][i];
    58         sort(c + 1, c + n + 1);
    59         build(1, n, 0);
    60         for(i = 1; i <= m; i++)
    61         {
    62             scanf("%d %d %d", &x, &y, &z);
    63             printf("%d
    ", query(1, n, 0, x, y, z));
    64         }
    65     }
    66     return 0;
    67 }
    View Code

    当然还有其他方法,不过代码量都比较大。

    可以看看这篇blog

  • 相关阅读:
    成为数据科学家并不难
    大数据分析的众包平台—Kaggle
    如何写一份好的数据分析报告
    配置java环境时,java的path地址放在其他地址的前面还是后面?
    js:随记
    JS:JSP Servlet
    [swustoj 1088] 德州扑克
    [swustoj 1092] 二分查找的最大次数
    [swustoj 371] 回文数
    [swustoj 1097] 2014
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6745158.html
Copyright © 2011-2022 走看看