PKU 2104 Kth-Number
最早见到这题是在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大来处理。
通过这个题目我知道了归并树的应用以及二分中一些细节的处理,这是以前不曾遇到的。
具体实现可参见我的代码:
- #include <iostream>
- using namespace std;
- const int N = 100010;
- struct node
- {
- int x, y;
- int dep;
- }seg[N<<3];
- int sorted[18][N];
- int n, m;
- int readData()
- {
- int ret = 0;
- char ch;
- bool dot = false,neg = false;
- while (((ch=getchar()) > '9' || ch < '0') && ch != '-') ;
- if (ch == '-') {
- neg = true;
- ch = getchar();
- }
- do {
- ret = ret*10 + (ch-'0');
- } while ((ch=getchar()) <= '9' && ch >= '0') ;
- return (neg? -ret : ret);
- }
- void build(int root, int x, int y, int depth)
- {
- seg[root] = (node){x, y, depth};
- if(x != y)
- {
- int mid = (x + y) >> 1;
- build(root * 2, x, mid, depth + 1);
- build(root * 2 + 1, mid + 1, y, depth + 1);
- int i = x, j = mid + 1, t = x;
- while(i <= mid || j <= y)
- {
- if(j > y || (i <= mid && sorted[depth+1][i] <= sorted[depth+1][j]))
- sorted[depth][t++] = sorted[depth+1][i++];
- else sorted[depth][t++] = sorted[depth+1][j++];
- }
- }
- else scanf("%d",&sorted[depth][x]);
- }
- int be, en, Kth;
- int query(int root, int x)
- {
- if(be <= seg[root].x && en >= seg[root].y)
- {
- int low = seg[root].x, up = seg[root].y;
- int d = seg[root].dep;
- if(x <= sorted[d][low]) return 0;
- else if(x > sorted[d][up]) return seg[root].y - seg[root].x + 1;
- while(low < up)
- {
- int mid = (low + up + 1) >> 1;
- if(sorted[d][mid] >= x) up = mid - 1;
- else low = mid;
- }
- return low - seg[root].x + 1;
- }
- else
- {
- int ans = 0;
- int mid = (seg[root].x + seg[root].y) >> 1;
- if(be <= mid) ans += query(root * 2, x);
- if(en > mid) ans += query(root * 2 + 1, x);
- return ans;
- }
- }
- int main()
- {
- int i, j;
- n = readData(), m = readData();
- build(1, 1, n, 0);
- for(; m; m--)
- {
- be = readData(), en = readData(), Kth = readData();
- int low = 1, up = n;
- while(up > low)
- {
- int mid = (up + low + 1) >> 1;
- if(query(1, sorted[0][mid]) >= Kth) up = mid - 1;
- else low = mid;
- }
- printf("%d/n",sorted[0][low]);
- }
- return 0;
- }
PKU 2104 Kth-Number相关推荐
- POJ 2104 K-th Number 主席树(区间第k大)
题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...
- POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)
题目链接: http://poj.org/problem? id=2104 解题思路: 由于查询的个数m非常大.朴素的求法无法在规定时间内求解. 因此应该选用合理的方式维护数据来做到高效地查询. 假设 ...
- 【转】POJ 2104 K-th Number(2)
转自: http://huangwei.host7.meyu.net/?p=24 题意:给定序列,求出[s,t]区间内第k小的数字. 解法:线段树+归并排序+二分枚举 Whu回来后,开始好好看了下其余 ...
- POJ 2104 K-th Number
题目地址 主席树+离散化 因为主席树空间开小了RE了两次,呜呜呜 一定要注意空间大小 1 #include<cstdio> 2 #include<algorithm> 3 #i ...
- POJ 2104 K-th Number 划分树
题意: 查询区间第\(k\)大 分析: 之前是用主席树做的,现在学一下划分树. 学习链接 划分树的空间复杂度为\(O(nlogn)\),这点比主席树更优. #include <cstdio> ...
- poj 2104: K-th Number 【主席树】
题目链接 学习了一下主席树,感觉具体算法思路不大好讲.. 大概是先建个空线段树,然后类似于递推,每一个都在前一个"历史版本"的基础上建立一个新的"历史版本",每 ...
- POJ - 2104 K-th Number(主席树)
题目链接:点击查看 题目大意:给出一个数列,然后是m次查询,每次查询闭区间[l,r]内第K大的数 题目分析:裸的主席树,暑假集训第三周的时候就听说过了这个数据结构,不过当时太懒了,而且那些主席树的问题 ...
- K-th Number
题目链接:http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Sub ...
- hdu 2665 Kth number(划分树模板)
http://acm.hdu.edu.cn/showproblem.php?pid=2665 [ poj 2104 2761 ] 改变一下输入就可以过 http://poj.org/problem? ...
- 划分树基础 —— HDU 2665 Kth number
对应 HDU 题目 :点击打开链接 Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K ...
最新文章
- 如何将 Nginx 性能提升10倍?这10个“套路”请收好!
- 数据解析1:XML解析(3)
- JavaSE(二十一)——栈和队列、栈和堆
- 高可用架构可行性方案
- C#绘制立体三维饼状图(超酷)
- excel 科学计数批量转换成文本
- xamarin android 标签,Xamarin.Android使用教程:Android项目结构
- AD转换器输入之前接一个电压跟随器是为什么?
- 深度卷积神经网络的过程详解——综述
- 学习笔记-极客时间 玩转 git 三剑客 课程记录
- 2022北京工业互联网安全大赛初赛-wakeup
- Aras Innovator: Catagoy, Itemtype, Item, Relationship的视图
- 总结谷歌身份验证器 Google Authenticator 的详细使用方法
- 跨境电商的商品是如何出口的-扬帆际海
- PyCharm连接MySQL数据库的时候,驱动下载失败
- 秋雨,在迷乱的思绪中飞扬
- 二叉树的公共祖先问题
- 【Linux网卡链路聚合】
- 学习 stm32 FATFS 系统文件函数使用和学习查看说明以及常用函数例程
- 动力环境集中监控系统的主要监控对象