poj 2104 K-th Number - 经典划分树
Description
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?
"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
Input
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
Output
Sample Input
- 7 3
- 1 5 2 6 3 7 4
- 2 5 3
- 4 4 1
- 1 7 3
Sample Output
- 5
- 6
- 3
Hint
This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.
题目意思:给一个数组。问一个区间内第K大的数。
解题思路:划分树。
划分树是基于高速排序的,首先将原始数组a[]进行排序sorted[],然后取中位数m,将未排序数组中小于m放在m左边,大于m的放在m右边,并记下原始数列中每一个数左边有多少数小于m,用数组to_left[depth][]表示,这就是建树过程。
重点在于查询过程。设[L,R]为要查询的区间,[l,r]为当前区间,s 表示[L,R]有多少数放到左子树,ss表示[l,L-1]有多少数被放倒左子树。假设s大于等于K,也就是说第K大的数肯定在左子树里。下一步就查询左子树,但这之前先要更新L,R,新的newl=l+ss,
newr=newl+s-1。假设s小于k,也就是说第k大的数在右子树里,下一步查询右子树,也要先更新L,R,dd表示[l,L-1]中有多少数被放到右子树,d表示[L,R]有多少数被放到右子树,那么newl = m+1+dd,newr=m+d+dd, 这样查询逐渐缩小查询区间,直到最后L==R 返回最后结果即可。
给出一个大牛的图片样例。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
代码:
- #include <cstdio>
- #include <algorithm>
- #include <iostream>
- using namespace std;
- #define maxn 100000+100
- int val[30][maxn];
- int to_left[30][maxn];
- int sorted[maxn];
- int n;
- void build(int l,int r,int d,int rt){
- if(l==r) return;
- int m = (l+r)>>1;
- int lsame = m-l+1;
- for(int i=l;i<=r;i++){
- if(val[d][i]<sorted[m]) lsame--;
- }
- int lpos=l,rpos=m+1,same=0;
- for(int i=l;i<=r;i++){
- if(i==l) to_left[d][i]=0;
- else to_left[d][i] = to_left[d][i-1];
- if(val[d][i]<sorted[m]){
- to_left[d][i]++;
- val[d+1][lpos++] = val[d][i];
- }else if(val[d][i]>sorted[m]){
- val[d+1][rpos++] = val[d][i];
- }else{
- if(same<lsame){
- same++;
- to_left[d][i]++;
- val[d+1][lpos++] = val[d][i];
- }else{
- val[d+1][rpos++] = val[d][i];
- }
- }
- }
- build(l,m,d+1,rt<<1);
- build(m+1,r,d+1,rt<<1|1);
- }
- void print(){
- printf("###\n");
- for(int i=0;i<10;i++){
- for(int j=1;j<=n;j++){
- cout << val[i][j]<<" ";
- }
- cout << endl;
- }
- printf("****\n");
- for(int i=0;i<10;i++){
- for(int j=1;j<=n;j++){
- cout << to_left[i][j]<<" ";
- }
- cout << endl;
- }
- }
- int query(int L,int R,int k,int l,int r,int d,int rt){
- if(L==R) return val[d][L];
- int s,ss;
- if(L==l){
- s = to_left[d][R];
- ss = 0;
- }else{
- s = to_left[d][R]-to_left[d][L-1];
- ss = to_left[d][L-1];
- }
- int m = (l+r)>>1;
- if(s>=k){
- int newl = l+ss;
- int newr = newl + s-1;
- return query(newl,newr,k,l,m,d+1,rt<<1);
- }else{
- int bb = (L-1)-l+1-ss;
- int b = R-L+1 -s;
- int newl = m+1+bb;
- int newr = m+bb+b; // 4 5 1 3 2 (2,5,4)
- return query(newl,newr,k-s,m+1,r,d+1,rt<<1|1);
- }
- }
- int main(){
- int m;
- scanf("%d %d",&n,&m);
- for(int i=1;i<=n;i++){
- scanf("%d",&val[0][i]);
- sorted[i]=val[0][i];
- }
- sort(sorted+1,sorted+n+1);
- build(1,n,0,1);
- // print();
- while(m--){
- int i,j,k;
- scanf("%d %d %d",&i,&j,&k);
- printf("%d\n",query(i,j,k,1,n,0,1));
- }
- return 0;
- }
poj 2104 K-th Number - 经典划分树的更多相关文章
- POJ 2104:K-th Number(主席树静态区间k大)
题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var ...
- poj 2104:K-th Number(划分树,经典题)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 35653 Accepted: 11382 Ca ...
- POJ 2104 K-th Number(划分树)
Description You are working for Macrohard company in data structures department. After failing your ...
- POJ 2104 K-th Number (划分树)
K-th Number Time Limit: 20000MS Memory ...
- hdu 2665 Kth number(划分树)
Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- poj2104 K-th Number(划分树)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 66068 Accepted: 23273 Ca ...
- 【POJ 2104】 K-th Number 主席树模板题
达神主席树讲解传送门:http://blog.csdn.net/dad3zz/article/details/50638026 2016-02-23:真的是模板题诶,主席树模板水过.今天新校网不好,没 ...
- K-th Number 【POJ - 2104】【可持久化线段树】
题目链接 因为这道题没有删除修改之类的,所以很多人会用离散化之后的线段树来做,但是实际上(可能是我懒得去做离散化这个操作了),然后就是直接写可持久化线段树,区间的长度就是int的从最小到最大的长度,然 ...
- POJ 2104:K-th Number(整体二分)
http://poj.org/problem?id=2104 题意:给出n个数和m个询问求区间第K小. 思路:以前用主席树做过,这次学整体二分来做.整体二分在yr大佬的指点下,终于大概懂了点了.对于二 ...
随机推荐
- 使程序能够引入.json文件, 为网站添加 MIME 映射
确认启用了 MIME 映射,或使用命令行工具 appcmd.exe 为网站添加 MIME 映射. 若要设置 MIME 类型,请在 IIS Express 安装目录中运行以下命令: appcmd set ...
- C++线性序列容器<vector>简单总结
C++线性序列容器<vector>简单总结 vector是一个长度可变的数组,使用的时候无须声明上限,随着元素的增加,Vector的长度会自动增加:Vector类提供额外的方法来增加.删除 ...
- php微信接口验证写法
<?php //获得接口认证 $timestamp = $_GET['timestamp']; $nonce = $_GET['nonce']; $token = 'weixin'; $sign ...
- linux FILE 类型.
stdio.h 头文件中,有以下内容(用内部行号解释): /* The opaque type of streams. This is the definition used elsewhere. * ...
- jquery读取后台代码
前台代码: <script type="text/javascript"> $(function () { $("#btn") ...
- PHP中检测ajax请求的代码例子
多数情况下,基于JavaScript 的Js框架如jquery.Mootools.Prototype等,在发出Ajax请求指令时,都会发送额外的 HTTP_X_REQUESTED_WITH 头部信息, ...
- ionic框架,快速开发webAPP神器。
官网地址 http://www.ionicframework.com/ 这个国外框架已经很火了.会使用插件的话更好,例如支付宝支付插件,调用摄像头拍照,二维码扫描,通讯录,文件上传,推送信息等等. 最 ...
- Cocos2d-x 使用物理引擎进行碰撞检测
[转自]: http://blog.csdn.net/cbbbc/article/details/38541099 通常在游戏简单逻辑判断和模拟真实的物理世界时,我们只需要在定时器中判断游戏中各个精灵 ...
- xml约束之schema
使用名称空间引入Schema : 通常需要在Xml文档中的根结点中使用schemaLocation属性来指定. <itcast:书架 xmlns:itcast="http://www. ...
- pdf转图片
public class FileUtil { public static void main(String[] args) { try { System.out.println(System.cur ...