POJ 2104为例

思想:

利用归并排序的思想:

  • 建树过程和归并排序类似,每个数列都是子树序列的合并与排序。
  • 查询过程,如果所查询区间完全包含在当前区间中,则直接返回当前区间内小于所求数的元素个数,否则递归的对子树进行求解并相加。
  • 使用STL中的merge对子序列进行合并及排序。
  • 时间复杂度O(nlogn+mlog3n)

代码(vector实现):

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<vector>
  4. #include<iostream>
  5. using namespace std;//[)
  6. const int maxn = 1000010;
  7. vector<int>dat[maxn*3];
  8. int sorted[maxn], a[maxn];
  9. void build(int k, int l, int r)
  10. {
  11. if(r - l == 1) dat[k].push_back(a[l]);
  12. else {
  13. int lch = 2 * k + 1, rch = 2 * k + 2;
  14. build(lch, l, (l + r)/2);
  15. build(rch, (l + r)/2, r);
  16. dat[k].resize(r - l);
  17. merge(dat[lch].begin(), dat[lch].end(), dat[rch].begin(), dat[rch].end(),dat[k].begin());
  18. }
  19. }
  20. int query(int l, int r, int x, int k, int L, int R)
  21. {
  22. if(r <= L|| l >= R) return 0;//不相交
  23. else if(l <= L && R <= r){//完全包含
  24. return lower_bound(dat[k].begin(), dat[k].end(), x) - dat[k].begin();
  25. }
  26. else {
  27. int lch = 2 * k + 1, rch = 2 * k + 2;
  28. int lsum = query(l, r, x, lch, L, (L + R)/2);
  29. int rsum = query(l, r, x, rch, (L + R)/2, R);
  30. return lsum + rsum;
  31. }
  32. }
  33. int main (void)
  34. {
  35. int n, m;scanf("%d%d",&n,&m);
  36. for(int i = 0; i < n; i++){
  37. scanf("%d",&a[i]);
  38. sorted[i] = a[i];
  39. }
  40. sort(sorted, sorted+n);
  41. build(0, 0, n);
  42. int tl, tr, k;
  43. while(m--){
  44. scanf("%d%d%d",&tl,&tr,&k);
  45. int l = 0, r = n;
  46. while(r - l >1){
  47. int mid = l + (r - l)/2;
  48. int c = query(tl-1, tr, sorted[mid], 0, 0 ,n);
  49. if(c <= k - 1 ) l = mid;
  50. else r = mid;
  51. }
  52. printf("%d\n", sorted[l]);
  53. }
  54. return 0;
  55. }//6000+ms

代码(数组实现):

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<vector>
  4. #include<iostream>
  5. using namespace std;//[)
  6. const int maxn = 1000010;
  7. int dat[20][3*maxn];
  8. int sorted[maxn], a[maxn];
  9. void build(int p, int l, int r)
  10. {
  11. if(r - l == 1) dat[p][l] = a[l];
  12. else {
  13. build(p+1, l, (l + r)/2);
  14. build(p+1, (l + r)/2, r);
  15. merge(dat[p+1] + l, dat[p+1] + (l + r)/2, dat[p+1] + (l + r)/2, dat[p+1] + r, dat[p]+l);
  16. }
  17. }
  18. int query(int l, int r, int x, int p, int L, int R)
  19. {
  20. if(r <= L|| l >= R) return 0;//不相交
  21. else if(l <= L && R <= r){//完全包含
  22. return lower_bound(dat[p]+L, dat[p]+R, x) - (dat[p]+L);
  23. }
  24. else {
  25. int lsum = query(l, r, x, p+1, L, (L + R)/2);
  26. int rsum = query(l, r, x, p+1, (L + R)/2, R);
  27. return lsum + rsum;
  28. }
  29. }
  30. int main (void)
  31. {
  32. int n, m;scanf("%d%d",&n,&m);
  33. for(int i = 0; i < n; i++){
  34. scanf("%d",&a[i]);
  35. sorted[i] = a[i];
  36. }
  37. sort(sorted, sorted+n);
  38. build(0, 0, n);
  39. int tl, tr, k;
  40. while(m--){
  41. scanf("%d%d%d",&tl,&tr,&k);
  42. int l = 0, r = n;
  43. while(r - l >1){
  44. int mid = l + (r - l)/2;
  45. int c = query(tl-1, tr, sorted[mid], 0, 0 ,n);
  46. if(c <= k - 1 ) l = mid;
  47. else r = mid;
  48. }
  49. printf("%d\n", sorted[l]);
  50. }
  51. return 0;
  52. }//2000+ms
  • 数组实现的要比vector快很多。
  • 归并树需要二分求解,但是划分树并不需要。因为划分树是从上到下,每次都用数组记录划分到左子树的元素个数,所以可以直接求得区间第k大数,而归并树是由下到上,每次对子树进行简单的合并和排序,并没有对划分到左子树的元素进行追踪,所以需要二分搜索答案,即线段树+二分。所以在求静态区间第k大时划分树也就比归并树要快。

静态区间第k大(归并树)的更多相关文章

  1. poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 43315   Accepted: 14296 Ca ...

  2. 主席树(静态区间第k大)

    前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建 ...

  3. 可持久化线段树(主席树)——静态区间第k大

    主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...

  4. HDU3473--Minimum Sum(静态区间第k大)

    Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  5. 主席树学习笔记(静态区间第k大)

    题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出 ...

  6. POJ2104-- K-th Number(主席树静态区间第k大)

    [转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249 无修改的区间第K大 我们先考虑简化的问题:我们要询问整个区间内的第K大.这样我们对值域建线段 ...

  7. HDU 2665 Kth number(主席树静态区间第K大)题解

    题意:问你区间第k大是谁 思路:主席树就是可持久化线段树,他是由多个历史版本的权值线段树(不是普通线段树)组成的. 具体可以看q学姐的B站视频 代码: #include<cmath> #i ...

  8. 主席树初步学习笔记(可持久化数组?静态区间第k大?)

    我接触 OI也快1年了,然而只写了3篇博客...(而且还是从DP跳到了主席树),不知道我这个机房吊车尾什么时候才能摸到大佬们的脚后跟orz... 前言:主席树这个东西,可以说是一种非常畸形的数据结构( ...

  9. POJ 2104 && POJ 2761 (静态区间第k大,主席树)

    查询区间第K大,而且没有修改. 使用划分树是可以做的. 作为主席树的入门题,感觉太神奇了,Orz /* *********************************************** ...

随机推荐

  1. Nexus3.0搭建私服上传JAR包 Windows10

    背景 近期换了一个项目组,用的是公司自研产品,涉及到很多内部JAR包引用,版本号很多,每次更新都是产品部给出jar包,项目组成员各自复制一套本地替换,来了新人各种安装配置,复杂度太高,这不,我一来,又 ...

  2. AJPFX关于modifier总结

    修饰符总结 Modifiers        函数修饰符始终在返回值类型之前!!!        变量修饰符始终在变量类型之前!!!---------------------------------- ...

  3. git --版本对比

    比较暂存区域和工作目录  -git diff 分别拷贝暂存区和工作目录的文件到a和b文件夹 ---   //表示旧文件  暂存区的 +++  //表示新文件   工作目录的 F 一页一页往下移 B 一 ...

  4. K近邻法(K-Nearest Neighbor,KNN)

    KNN是一种基本分类与回归方法,本篇只总结分类问题中的KNN. 输入:样本的特征向量,对应于特征空间中的点 输出:样本的类别,可取多类 算法思想:给定一个样本类别已知的训练数据集,对于新样本,根据其K ...

  5. 00C#

    C# C#(读作“See Sharp”)是一种简单.现代.面向对象且类型安全的编程语言.C# 起源于 C 语言家族,因此,对于 C.C++ 和 Java 程序员,可以很快熟悉这种新的语言.C# 已经分 ...

  6. 模板—trie图

    做了某题之后发现trie的AC自动机太垃圾了,动不动就TLE,然后我就去学了trie图. #include<iostream> #include<cstdio> using n ...

  7. iOS网络图片缓存SDWebImage

    Web image(网络图像) 该库提供了一个支持来自Web的远程图像的UIImageView类别 它提供了: 添加网络图像和缓存管理到Cocoa Touch framework的UIImageVie ...

  8. MySQL和Oracle的比较

    可以从以下几个方面来进行比较: (1) 对事务的提交    MySQL默认是自动提交,而Oracle默认不自动提交,需要用户手动提交,需要在写commit;指令或者点击commit按钮(2) 分页查询 ...

  9. c++基础_回文数

    #include <iostream> using namespace std; int main(){ ;i<;i++){ ; int n=i;//暂存该四位数来计算 ,以防改变i ...

  10. 有向图连通分量SCC

    在无向图中,如果从顶点vi到顶点vj有路径,则称vi和vj连通.如果图中任意两个顶点之间都连通,则称该图为连通图,否则,称该图为非连通图,则其中的极大连通子图称为连通分量,这里所谓的极大是指子图中包含 ...