K-th Number 线段树(归并树)+二分查找
题意:给定一个包含n个不同数的数列a1, a2, ..., an 和m个三元组表示的查询。对于每个查询(i, j, k), 输出ai, ai+1, ... ,aj的升序排列中第k个数 。
题解:用线段树,每个节点维护一个区间并且保证内部升序,对于每次查询x,返回该区间小于x的数的个数。就这样不断二分,直到找到x为止。
线段树(归并树)+二分查找
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF=0x4fffffff;
const int EXP=1e-;
const int MS=; struct node
{
int l,r;
vector<int> vec;
}nodes[*MS]; int a[MS];
int num[MS];
int n,m; void build(int root,int l,int r)
{
nodes[root].l=l;
nodes[root].r=r;
nodes[root].vec.clear();
if(r-l==)
{
nodes[root].vec.push_back(a[l]);
return ;
}
int mid=(l+r-)>>;
build(root<<,l,mid+);
build(root<<|,mid+,r);
nodes[root].vec.resize(r-l);
merge(nodes[root<<].vec.begin(),nodes[root<<].vec.end(),
nodes[root<<|].vec.begin(),nodes[root<<|].vec.end(),nodes[root].vec.begin());
} int query(int root,int l,int r,int x)
{
if(r<=nodes[root].l||nodes[root].r<=l)
return ;
else if(nodes[root].l>=l&&nodes[root].r<=r)
return upper_bound(nodes[root].vec.begin(),nodes[root].vec.end(),x)-nodes[root].vec.begin();
else
{
int lcnt=query(root<<,l,r,x);
int rcnt=query(root<<|,l,r,x);
return lcnt+rcnt;
}
} int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=;i<n;i++)
{
scanf("%d",&a[i]);
num[i]=a[i];
}
sort(num,num+n);
build(,,n);
int s,t,k;
for(int i=;i<m;i++)
{
scanf("%d%d%d",&s,&t,&k);
s--;
int l=-,r=n-;
/* 注意 根据问题特点,这里应该是l=-1,r=n-1.
如果情况是询问[l,n]这个区间第n-l+1大的值,并且这个值在最后的位置,那么最后的结果会是num[n],越界
也就是说 二分的结果总是l=mid,知道r-l<=1; 细节问题需要注意
*/
while(r-l>)
{
int mid=(l+r)>>;
int cnt=query(,s,t,num[mid]);
if(cnt>=k)
r=mid;
else
l=mid;
}
printf("%d\n",num[r]);
}
}
return ;
}
我写的块状数组超时了。不知道是算法真的超时,还是细节问题导致超时。日后再来改正。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long LL;
const int INF=0x4fffffff;
const int EXP=1e-;
const int MS=;
const int SIZE=; int n,m;
int a[MS];
int order[MS]; vector<int> bucket[MS/SIZE]; int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=;i<MS/SIZE;i++)
bucket[i].clear(); // 千万注意清空
for(int i=;i<n;i++)
{
scanf("%d",&a[i]);
bucket[i/SIZE].push_back(a[i]);
order[i]=a[i];
}
sort(order,order+n);
for(int i=;i<n/SIZE;i++)
sort(bucket[i].begin(),bucket[i].end());
int s,t,k;
while(m--)
{
scanf("%d%d%d",&s,&t,&k);
s--; //[s,t) 二分查找使用左必有开更方便一些
int l=-,r=n-; // 注意: 根据问题的性质,l=0,r=n是错误的,因为有情况总是mid=l,一直到到
// n-l<=1, 这时答案是num[n],不在给定的数组范围内了。
while(r-l>)
{
int mid=(l+r)>>;
int x=order[mid];
int tl=s,tr=t,c=;
// 处理区间两端多出的部分
while(tl<tr&&tl%SIZE!=)
if(a[tl++]<=x)
c++;
while(tl<tr&&tr%SIZE!=) // 左闭右开 处理方便一些
if(a[--tr]<=x)
c++;
// 对每一个桶进行统计
while(tl<tr)
{
int id=tl/SIZE;
c+=upper_bound(bucket[id].begin(),bucket[id].end(),x)-bucket[id].begin();
tl+=SIZE;
}
if(c>=k)
r=mid;
else
l=mid;
}
printf("%d\n",order[r]);
}
}
return ;
}
K-th Number 线段树(归并树)+二分查找的更多相关文章
- HDU-4614 Vases and Flowers(线段树区间更新+二分查找)
http://acm.hdu.edu.cn/showproblem.php?pid=4614 Time Limit: 4000/2000 MS (Java/Others) Memory Limi ...
- 线段树离散化 unique + 二分查找 模板 (转载)
离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率. 通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小.例如: 原数据:1,999,100000,15:处理 ...
- 洛谷P4332 [SHOI2014]三叉神经树(LCT,树剖,二分查找,拓扑排序)
洛谷题目传送门 你谷无题解于是来补一发 随便百度题解,发现了不少诸如树剖\(log^3\)LCT\(log^2\)的可怕描述...... 于是来想想怎么利用题目的性质,把复杂度降下来. 首先,每个点的 ...
- POJ 2182 Lost Cows (树状数组 && 二分查找)
题意:给出数n, 代表有多少头牛, 这些牛的编号为1~n, 再给出含有n-1个数的序列, 每个序列的数 ai 代表前面还有多少头比 ai 编号要小的牛, 叫你根据上述信息还原出原始的牛的编号序列 分析 ...
- PAT-1057 Stack (树状数组 + 二分查找)
1057. Stack Stack is one of the most fundamental data structures, which is based on the principle of ...
- leetcode-374-Guess Number Higher or Lower(二分查找)
题目描述: We are playing the Guess Game. The game is as follows: I pick a number from 1 to n. You have t ...
- (经典) K&R的名著<<C程序设计语言>>二分查找
#include<stdio.h> //查找成功则返回所在下标否则返回-1 int binsearch(int A[], int n,int a) { int low, high, mid ...
- toj 4353 Estimation(树状数组+二分查找)
Estimation 时间限制(普通/Java):5000MS/15000MS 运行内存限制:65536KByte总提交: 6 测试通过: 1 描述 “There are ...
- 树状数组+二分||线段树 HDOJ 5493 Queue
题目传送门 题意:已知每个人的独一无二的身高以及排在他前面或者后面比他高的人数,问身高字典序最小的排法 分析:首先对身高从矮到高排序,那么可以知道每个人有多少人的身高比他高,那么取较小值(k[i], ...
- 离散化+线段树/二分查找/尺取法 HDOJ 4325 Flowers
题目传送门 题意:给出一些花开花落的时间,问某个时间花开的有几朵 分析:这题有好几种做法,正解应该是离散化坐标后用线段树成端更新和单点询问.还有排序后二分查找询问点之前总花开数和总花凋谢数,作差是当前 ...
随机推荐
- 第三百二十八天 how can I 坚持
今天电脑快把我搞疯了,一天得死机快十次,不知道怎么回事,最后升级了win10,感觉就是比较好. 哎,成了这个样子,当初为什么又让我抽中了那个签,搞不懂啊,这都是为啥. 我哪里错了,还是冥冥中自有天意, ...
- 解析XtraBackup备份MySQL的原理和过程(转)
原文:http://ourlinux.blog.51cto.com/274624/844859 XtraBackup是percona公司提供的开源工具,以热备Innodb表著称而被广泛采用. Xtra ...
- 全球各大运营商黑莓ROM官网下载链接汇总
全球各大运营商黑莓ROM官网下载链接汇总: 先来关于8830的. 4.2.2.196的rom 8830EFS_PBr4.2.2_rel365_PL3.0.0.85_A4.2.2.196_Sprint ...
- flask中的request对象方法
'accept_charsets','accept_encodings','accept_languages','accept_mimetypes','access_route','applicati ...
- oracle关键字使用
v_Describe:=substr(v_Describe,0,length(v_Describe)-1); substr(目标内容,开始位置,截取长度) length(要计算的内容长度) 上述语句可 ...
- How Tomcat Works(九)
本文接下来描述servlet容器是怎样管理其相关组件的生命周期的,首先本人描述一下事件监听模式,也可以称为观察者模式,该模式分为以下角色 即抽象主题角色 具体主题角色 抽象观察者角色及具体观察者角色, ...
- Oracle数据库编程:使用PL/SQL编写触发器
8.使用PL/SQL编写触发器: 触发器存放在数据缓冲区中. 触发器加序列能够实现自动增长. 在触发器中不能使用connit和rollback. DML触发器 ...
- c++中智能输出文件
首先我们要为每一时间步,设置一个文件名: ] = "; itoa(time,timestr,); std::string s; s += timestr; std::string path ...
- jsp中使用动态数据进行mySQL数据库的两种操作方法
使用动态数据进行数据库内容的增删改查操作有两种方法: 在此定义数据库连接为conn 假设有表单进行数据输入并提交到处理页面一种是使用预编译格式: 其格式如下: String name = reques ...
- nginx 配置虚拟主机(支持php)
配置步骤: 1.在nginx安装目录下,找到nginx.conf所在文件夹,新建vhost文件夹 2.在nginx.conf http{} 末端加入 include vhost/*.conf; 3.进 ...