最早见到这题是在07年JSOI冬令营上,当时知道了个大概,最近才弄明白,惭愧。。。

题意很简单,询问长度为100000的数组中给定区间上的第K大值

1. 考虑子问题,对于给定的数x,如何求出在给定区间上比x小的数有多少个(即x的排名)

2. 如果问题1得到解决,那么我们可以通过对排序过的原数组进行二分答案,直到找到一个数y,使得它在给定区间上的排名为K

本题使用线段树的思想(更严格的说,应该是归并树),树中每个节点(线段)保存该区间内原数值的有序序列。

例如原区间上的数为 2, 5, 3 那么,最终该区间上保存的数值是2,3,5. 其实并不需要存下这么多数,只需要保留一个索引(在有序数组中两端的位置)即可。这一步其实就是一个归并排序的过程。

对于给定一个数,我们查询其在给定区间上的排名。如果该区间正好覆盖了线段树的一个节点,那么直接进行二分查找即可。

如果不覆盖,只需要分别递归进入子区间,最终的排名即是两个子区间排名之和。

以上即是本题的基本算法。在我看来,这个题目的繁琐之处在于二分查找的部分。

第一个二分查找:

这是在二分答案的时候。举例: 如果给定区间上的数是2, 5, 10, 要求第三大

如果我们二分的答案是6,7,8,9,10,算出的排名都会是3. 这个时候我们要选最大的一个。

第二个二分查找:

这是在给定区间上二分查找排名的时候。其实就是查找比给定数值小的数的个数。这个时候如果遇上和给定数x相同的数,应当算作比x大来处理。

通过这个题目我知道了归并树的应用以及二分中一些细节的处理,这是以前不曾遇到的。

具体实现可参见我的代码:

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 100010;
  4. struct node
  5. {
  6. int x, y;
  7. int dep;
  8. }seg[N<<3];
  9. int sorted[18][N];
  10. int n, m;
  11. int readData()
  12. {
  13. int ret = 0;
  14. char ch;
  15. bool dot = false,neg = false;
  16. while (((ch=getchar()) > '9' || ch < '0') && ch != '-') ;
  17. if (ch == '-') {
  18. neg = true;
  19. ch = getchar();
  20. }
  21. do {
  22. ret = ret*10 + (ch-'0');
  23. } while ((ch=getchar()) <= '9' && ch >= '0') ;
  24. return (neg? -ret : ret);
  25. }
  26. void build(int root, int x, int y, int depth)
  27. {
  28. seg[root] = (node){x, y, depth};
  29. if(x != y)
  30. {
  31. int mid = (x + y) >> 1;
  32. build(root * 2, x, mid, depth + 1);
  33. build(root * 2 + 1, mid + 1, y, depth + 1);
  34. int i = x, j = mid + 1, t = x;
  35. while(i <= mid || j <= y)
  36. {
  37. if(j > y || (i <= mid && sorted[depth+1][i] <= sorted[depth+1][j]))
  38. sorted[depth][t++] = sorted[depth+1][i++];
  39. else sorted[depth][t++] = sorted[depth+1][j++];
  40. }
  41. }
  42. else scanf("%d",&sorted[depth][x]);
  43. }
  44. int be, en, Kth;
  45. int query(int root, int x)
  46. {
  47. if(be <= seg[root].x && en >= seg[root].y)
  48. {
  49. int low = seg[root].x, up = seg[root].y;
  50. int d = seg[root].dep;
  51. if(x <= sorted[d][low]) return 0;
  52. else if(x > sorted[d][up]) return seg[root].y - seg[root].x + 1;
  53. while(low < up)
  54. {
  55. int mid = (low + up + 1) >> 1;
  56. if(sorted[d][mid] >= x) up = mid - 1;
  57. else low = mid;
  58. }
  59. return low - seg[root].x + 1;
  60. }
  61. else
  62. {
  63. int ans = 0;
  64. int mid = (seg[root].x + seg[root].y) >> 1;
  65. if(be <= mid) ans += query(root * 2, x);
  66. if(en > mid) ans += query(root * 2 + 1, x);
  67. return ans;
  68. }
  69. }
  70. int main()
  71. {
  72. int i, j;
  73. n = readData(), m = readData();
  74. build(1, 1, n, 0);
  75. for(; m; m--)
  76. {
  77. be = readData(), en = readData(), Kth = readData();
  78. int low = 1, up = n;
  79. while(up > low)
  80. {
  81. int mid = (up + low + 1) >> 1;
  82. if(query(1, sorted[0][mid]) >= Kth) up = mid - 1;
  83. else low = mid;
  84. }
  85. printf("%d/n",sorted[0][low]);
  86. }
  87. return 0;
  88. }

PKU 2104 Kth-Number相关推荐

  1. POJ 2104 K-th Number 主席树(区间第k大)

    题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...

  2. POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)

    题目链接: http://poj.org/problem? id=2104 解题思路: 由于查询的个数m非常大.朴素的求法无法在规定时间内求解. 因此应该选用合理的方式维护数据来做到高效地查询. 假设 ...

  3. 【转】POJ 2104 K-th Number(2)

    转自: http://huangwei.host7.meyu.net/?p=24 题意:给定序列,求出[s,t]区间内第k小的数字. 解法:线段树+归并排序+二分枚举 Whu回来后,开始好好看了下其余 ...

  4. POJ 2104 K-th Number

    题目地址 主席树+离散化 因为主席树空间开小了RE了两次,呜呜呜 一定要注意空间大小 1 #include<cstdio> 2 #include<algorithm> 3 #i ...

  5. POJ 2104 K-th Number 划分树

    题意: 查询区间第\(k\)大 分析: 之前是用主席树做的,现在学一下划分树. 学习链接 划分树的空间复杂度为\(O(nlogn)\),这点比主席树更优. #include <cstdio> ...

  6. poj 2104: K-th Number 【主席树】

    题目链接 学习了一下主席树,感觉具体算法思路不大好讲.. 大概是先建个空线段树,然后类似于递推,每一个都在前一个"历史版本"的基础上建立一个新的"历史版本",每 ...

  7. POJ - 2104 K-th Number(主席树)

    题目链接:点击查看 题目大意:给出一个数列,然后是m次查询,每次查询闭区间[l,r]内第K大的数 题目分析:裸的主席树,暑假集训第三周的时候就听说过了这个数据结构,不过当时太懒了,而且那些主席树的问题 ...

  8. K-th Number

    题目链接:http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Sub ...

  9. hdu 2665 Kth number(划分树模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=2665 [ poj 2104 2761 ]  改变一下输入就可以过 http://poj.org/problem? ...

  10. 划分树基础 —— HDU 2665 Kth number

    对应 HDU 题目 :点击打开链接 Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

最新文章

  1. 如何将 Nginx 性能提升10倍?这10个“套路”请收好!
  2. 数据解析1:XML解析(3)
  3. JavaSE(二十一)——栈和队列、栈和堆
  4. 高可用架构可行性方案
  5. C#绘制立体三维饼状图(超酷)
  6. excel 科学计数批量转换成文本
  7. xamarin android 标签,Xamarin.Android使用教程:Android项目结构
  8. AD转换器输入之前接一个电压跟随器是为什么?
  9. 深度卷积神经网络的过程详解——综述
  10. 学习笔记-极客时间 玩转 git 三剑客 课程记录
  11. 2022北京工业互联网安全大赛初赛-wakeup
  12. Aras Innovator: Catagoy, Itemtype, Item, Relationship的视图
  13. 总结谷歌身份验证器 Google Authenticator 的详细使用方法
  14. 跨境电商的商品是如何出口的-扬帆际海
  15. PyCharm连接MySQL数据库的时候,驱动下载失败
  16. 秋雨,在迷乱的思绪中飞扬
  17. 二叉树的公共祖先问题
  18. 【Linux网卡链路聚合】
  19. 学习 stm32 FATFS 系统文件函数使用和学习查看说明以及常用函数例程
  20. 动力环境集中监控系统的主要监控对象

热门文章

  1. codeforces 839C Journey
  2. java holder_这个Holder 在Java中做什么? - java
  3. opencv血管分割——边缘检测
  4. MATLAB固定工业相机曝光时间和增益系数
  5. 2021年特种作业操作证电工作业-继电保护考试题库
  6. 直驱式永磁同步风力发电机系统建模与仿真,matlab,simulink仿真,直驱,永磁,风力发电
  7. python3d相册源代码_js和CSS3炫酷3D相册展示
  8. MyBatis作业,以下三个问题,任选两个作答
  9. 月饼之王花落谁手?全网都在销售它!
  10. python培训千峰