转自: http://huangwei.host7.meyu.net/?p=24

题意:给定序列,求出[s,t]区间内第k小的数字。

解法:线段树+归并排序+二分枚举

Whu回来后,开始好好看了下其余题目,感觉区间k大数应该有经典算法,问了下linle才知道poj上有原题,实在郁闷。比赛时也想到了线段树,但是没考虑到开另一个空间去保存排序后的值,所以一直没法打开思路。

(1)用线段树来表示区间,构造线段树O(NlogN),这样能在O(logN)时间内确定区间的最大值。

(2)另外保存了排序后的值后,那给定一个值,可以在区间内查找从而得出该值排序后的位置,这里可以用二分查找,复杂度又乘上了O(logN)。这儿要注意的是如果存在两个或多个相同值的时候应该输出最小的位置,自然得可以理解为并列名次。

(3)题目要求输出区间内指定名次的数值。我们从上面可以由一个值来确定名次,显然这个名次在排序后的序列中是非递减的,所以这儿又可以二分枚举,在排序后的序列中二分枚举一个数值,用(2)的方法得出名次,和指定的名次进行比较。这里的二分和(2)的二分对相同值的处理不同,这里要取相同值的最大位置,原因是当非区间内的数比区间内的数大时,才使得名次+1。

(4)最后的时间复杂度是O(MlogNlogNlogN)

听说有不需造线段树的方法,继续研究……

Sample

Num

1

5

2

6

3

7

4

Sorted

1

2

3

4

5

6

7

Query 1

 

2

3

5

6

   

Rank 1

1

1

2

3

3

4

5

Query 2

     

6

     

Rank 2

1

1

1

1

1

1

2

Query 3

1

2

3

4

5

6

7

Rank 3

1

2

3

4

5

6

7

下载: pku2104.cpp

//POJ 2104

#include <cstdio>

#include <string>

#include <vector>

#include <algorithm>

using namespace std;

const int NMAX = 100000;

const int LOGNMAX = 17 +1;

int sortseq[LOGNMAX][NMAX];

int num[NMAX];

struct node {

int l,r,d;

node * pl,* pr;

}mem[(NMAX<<1)+100];

int mempos,n,m;

node * root;

node * make_tree(int l,int r,int d) {

node * rt = mem+(mempos ++);

rt->l = l; rt->r = r; rt->d = d;

if (l == r) {

sortseq[d][l] = num[l];

return rt;

}

int mid = (l+r) >> 1;

rt->pl = make_tree(l,mid,d+1);

rt->pr = make_tree(mid+1,r,d+1);

int i=l,j=mid+1,k=l;

while (i<=mid && j<=r) {

if (sortseq[d+1][i] < sortseq[d+1][j]) sortseq[d][k++] = sortseq[d+1][i++];

else sortseq[d][k++] = sortseq[d+1][j++];

}

while (i<=mid) sortseq[d][k++] = sortseq[d+1][i++];

while (j<=r) sortseq[d][k++] = sortseq[d+1][j++];

return rt;

}

int s,t,rank;

int query(node * rt,int val) {

int i,mid,ret;

if (s <= rt->l && rt->r <= t) {

if (val <= sortseq[rt->d][rt->l]) return 0;

else if (sortseq[rt->d][rt->r] < val) return rt->r - rt->l +1;

else if (sortseq[rt->d][rt->r] == val) return rt->r - rt->l;

int l = rt->l, r = rt->r, mid;

while (l <= r) {

mid = (l+r) >> 1;

if (val <= sortseq[rt->d][mid]) r = mid-1;

else l = mid+1;

}

return l - rt->l;

}

else {

ret = 0;

mid = (rt->l+rt->r) >> 1;

if (s <= mid) ret += query(rt->pl,val);

if (mid+1 <= t) ret += query(rt->pr,val);

return ret;

}

}

int get_val() {

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);

}int main() {

int i,j,l,r;

n = get_val(); m = get_val();

for (i=0;i<n;i++) num[i] = get_val();

mempos = 0;

root = make_tree(0,n-1,0);

while (m --) {

s = get_val()-1; t = get_val()-1; rank = get_val()-1;

l = 0, r = n-1;

while (l <= r) {

int mid = (l+r) >> 1;

int pos = query(root,sortseq[0][mid]);

if (rank < pos) r = mid-1;

else l = mid+1;

}

printf("%d\n",sortseq[0][r]);

}

}

转载于:https://www.cnblogs.com/lzhitian/archive/2012/08/01/2618099.html

【转】POJ 2104 K-th Number(2)相关推荐

  1. ACM练级日志:可持久化线段树初级-POJ 2104

    近期决定把数据结构技能树继续开发下去,学习更深入层次的三项技能:可持久化线段树.动态树.树链剖分.然后那天看了看动态树,碎了,然后就去看可持久化线段树了-- 简单地说,这玩意是一个可以保存修改的历史版 ...

  2. K - The Number of Products

    K - The Number of Products 题目入口:K - The Number of Products Codeforces:B. The Number of Products 参考网站 ...

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

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

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

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

  5. POJ 2104 K-th Number

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

  6. POJ 2104 K-th Number 划分树

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

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

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

  8. 【划分树】 POJ 2104 HDU 2665 K-th Number 裸题

    了解了.... #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ma ...

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

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

最新文章

  1. 解题报告:AcWing 352. 闇の連鎖(树上差分、方案统计)
  2. 心脏病预测模型(基于Python的数据挖据)
  3. bootstrap图片叠加_图片 | Images
  4. python写好的代码怎么给别人使用-10分钟学会用python写游戏!Python其实很简单!...
  5. iOS 设置button文字过长而显示省略号的解决办法
  6. 使用VideoView做个实用的视频播放器
  7. Android 上下滚动字幕实现
  8. hive复合数据类型之array
  9. 年底了,各大电商大促会员活动反馈万能模板,必备的PSD分层格式
  10. 去掉iframe的水平滚动条而保留垂直滚动条
  11. java如何求上个月的最后一天是多少号_JAVA入门题
  12. duilib菜单动态添加
  13. 高德地图API:如何根据经纬度获取位置信息
  14. 益聚星荣:一文看懂,为什么有的投资人讨厌元宇宙,有的却爱死它了
  15. 微信小程序基于mpvue的ui组件之选择器
  16. 订阅号微信公众号历史文章爬虫php,2019.9月最新爬取微信公众号历史文章的办法...
  17. 脉宽调制(PWM)的基本原理及其应用实例
  18. [杂项][原创]京东史上最差一次购物体验:一款神奇笔记本电脑机械革命x10ti
  19. 03-盒子模型与元素显示类型
  20. 已拥有阿里云服务器和域名,怎样搭建网站?

热门文章

  1. Linux下各文件夹的结构说明及用途介绍(转载)
  2. java实现八种排序算法并测试速度(详细)
  3. 网络编程中的大端和小端
  4. 在hibernate中使用c3p0数据源
  5. javascript中的constructor
  6. MalformedObjectNameException: Invalid character '' in value part of property
  7. Android自动化测试之路——Provider(一)
  8. C# 从DataSet导出到Excel
  9. 【LeetCode】121.买卖股票的最佳时机
  10. 错误: (串列)对象不能强制改变成'double'解决办法