POJ2104 (平方分割)二分查找理解。
题意:任意区间求第k大数
思路:
预处理:利用平方分割(分桶法)把区间切割成B = sqrt(n)大小的一块块,然后每个各自排序。
二分第k大数x,接着就需要求[l,r]区间中x的排名,与k比较,将两边端点非完整桶的点进行扫描,最多B次,其余每个桶进行二分查找排名,可利用upper_bound(STL)即可快速实现。
评价:
二分确实坑爹,不过搞了这一题也算对二分查找理解深入了些。
二分正确做法:
对于[0..n-1)有[0..m]满足性质其余不满足, 则应用[l, r)进行二分查找, 最后l一定是正确的。总是保证l不成立,r成立。
l = -, r = n;
while(l < r-)
{
int mid = (l+r)/;
if(check(mid))
l = mid;
else
r = mid;
}
cout << l << endl;
而若是[m, n-1]满足性质, 则应用(l, r]进行二分查找, 最后r一定正确,反之即可。
保证(l, r]正确性
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <vector>
#include <queue>
#include <map>
#include <set>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 0x3f3f3f3f
#define MAXN 200005
#define B 1000 using namespace std; vector<int> bucket[MAXN/B];
int a[MAXN], q[MAXN], n, m, x, y, k; int main()
{
scanf("%d%d", &n, &m);
for(int i = ; i < n; i ++)
{
scanf("%d", &a[i]);
q[i] = a[i];
bucket[i/B].push_back(a[i]);
}
sort(q, q+n);
for(int i = ; i < MAXN/B; i ++)
sort(bucket[i].begin(), bucket[i].end());
while(m --)
{
scanf("%d%d%d", &x, &y, &k);
x--, y;
int l = -, r = n-; //(l, r]
while(l < r-)
{
int mid = (l+r)/;
int tx = x, ty = y;
int cnt = ;
for( ; tx < ty && tx%B != ; tx ++)
if(a[tx] <= q[mid]) cnt ++;
for( ; tx < ty && ty%B != ; ty --)
if(a[ty-] <= q[mid]) cnt ++;
for(int i = tx/B; i < ty/B; i ++)
cnt += upper_bound(bucket[i].begin(), bucket[i].end(), q[mid])-bucket[i].begin();
if(k <= cnt)
r = mid;
else
l = mid;
}
if(r < )
printf("-1");
else
printf("%d\n", q[r]);
}
return ;
}
例如本题若换成[l, r)正确性,稍加改动即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <vector>
#include <queue>
#include <map>
#include <set>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 0x3f3f3f3f
#define MAXN 200005
#define B 1000 using namespace std; vector<int> bucket[MAXN/B];
int a[MAXN], q[MAXN], n, m, x, y, k; int main()
{
scanf("%d%d", &n, &m);
for(int i = ; i < n; i ++)
{
scanf("%d", &a[i]);
q[i] = a[i];
bucket[i/B].push_back(a[i]);
}
sort(q, q+n);
for(int i = ; i < MAXN/B; i ++)
sort(bucket[i].begin(), bucket[i].end());
while(m --)
{
scanf("%d%d%d", &x, &y, &k);
x--, y;
int l = , r = n; //[l, r)
while(l < r-)
{
int mid = (l+r)/;
int tx = x, ty = y;
int cnt = ;
for( ; tx < ty && tx%B != ; tx ++)
if(a[tx] < q[mid]) cnt ++;
for( ; tx < ty && ty%B != ; ty --)
if(a[ty-] < q[mid]) cnt ++;
for(int i = tx/B; i < ty/B; i ++)
cnt += lower_bound(bucket[i].begin(), bucket[i].end(), q[mid])-bucket[i].begin();
if(cnt < k)
l = mid;
else
r = mid;
}
printf("%d\n", q[l]);
}
return ;
}
POJ2104 (平方分割)二分查找理解。的更多相关文章
- 静态区间第k大(分桶法和平方分割)
POJ 2104为例 思想: <挑战程序设计竞赛>中介绍的方法. 分桶法:把一排物品或者平面分成桶,每个桶分别维护自己内部的信息,已达到高效计算的目的. 设一共有n个数,每b个分到一个桶里 ...
- POJ2104 K-th Number 静态区间第k最值 平方分割
干掉这道题的那一刻,我只想说:我终于**的AC了!!! 最终内存1344K,耗时10282ms,比起归并树.划分树以及其他各种黑科技,这个成绩并不算光彩⊙﹏⊙ 但至少,从最初的无数次TLE到最终的AC ...
- 二分查找——没有想象中的容易(详解各种变式,超深度理解,c++)
int binarySearch(int[] nums, int target) { int left = 0; int right = nums.length - 1; // 注意 while(le ...
- 从一个NOI题目再学习二分查找。
二分法的基本思路是对一个有序序列(递增递减都可以)查找时,测试一个中间下标处的值,若值比期待值小,则在更大的一侧进行查找(反之亦然),查找时再次二分.这比顺序访问要少很多访问量,效率很高. 设:low ...
- StringBuffer、StringBuilder、冒泡与选择排序、二分查找、基本数据类型包装类_DAY13
1:数组的高级操作(预习) (1)数组:存储同一种数据类型的多个元素的容器. (2)特点:每个元素都有从0开始的编号,方便我们获取.专业名称:索引. (3)数组操作: A:遍历 public stat ...
- 实现 sqrt(x):二分查找法和牛顿法
最近忙里偷闲,每天刷一道 LeetCode 的简单题保持手感,发现简单题虽然很容易 AC,但若去了解其所有的解法,也可学习到不少新的知识点,扩展知识的广度. 创作本文的思路来源于:LeetCode P ...
- js基本算法:冒泡排序,二分查找
知识扩充: 时间复杂度:算法的时间复杂度是一个函数,描述了算法的运行时间.时间复杂度越低,效率越高. 自我理解:一个算法,运行了几次时间复杂度就为多少,如运行了n次,则时间复杂度为O(n). 1.冒泡 ...
- 用c语言编写二分查找法
二分法的适用范围为有序数列,这方面很有局限性. #include<stdio.h> //二分查找法 void binary_search(int a[],int start,int mid ...
- 二分查找算法java实现
今天看了一下JDK里面的二分法是实现,觉得有点小问题.二分法的实现有多种今天就给大家分享两种.一种是递归方式的,一种是非递归方式的.先来看看一些基础的东西. 1.算法概念. 二分查找算法也称为折半搜索 ...
随机推荐
- viewFlipper 之二
main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xml ...
- 10、property
成人的BMI数值:过轻:低于18.5正常:18.5-23.9过重:24-27肥胖:28-32非常肥胖, 高于32 体质指数(BMI)=体重(kg)÷身高^2(m) EX:70kg÷(1.75×1.75 ...
- AngularJS多模块开发与路由
这里只是做一个笔记 angularjs模块(父子级)比如我有一个项目叫做shcool,那么我school下边有两个模块,student.teacher.此时school就属于主模块,其他都是子模块.子 ...
- 常用RDD
只作为我个人笔记,没有过多解释 Transfor map filter filter之后,依然有三个分区,第二个分区为空,但不会消失 flatMap reduceByKey groupByKey() ...
- kafka的javaapi生产者生产消息,消费者获取不到
zookeeper和kafka的日志没有出现什么报错 linux下kafka的命令行能生产并收到消费消息 但是在idea(windows环境下)中,调用api,获取不到数据,也生产不了数据,现象就是没 ...
- Uninstalling JIRA applications from Linux
If you wish to re-install JIRA in 'unattended mode', do not uninstall your previous installation of ...
- Dbus组成和原理
DBUS是实质上一个适用于桌面应用的进程间的通讯机制,即所谓的IPC机制.适合在同一台机器,不适合于INTERNET的IPC机制.DBUS不是一个为所有可能的应用的通用的IPC机制,不支持其他IPC机 ...
- Redis学习笔记之Redis单机,伪集群,Sentinel主从复制的安装和配置
0x00 Redis简介 Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure server). Redis的键值 ...
- JAVA学习笔记之JAVA 对象引用以及赋值
关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没 ...
- Junit中的setup和teardown方法
setup需要@before注解,实现测试前的初始化工作 teardown需要@after注解,测试完成后垃圾回收等后续工作