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 坚持
下午去打了会篮球,好累,又把android开发环境搭建起来了,明天把天气应用搞起来. 今天老妈打电话说昨晚梦到我小时候了.. 是啊,都这么大了,不能让他们老操心了. 过两天买根鱼竿去钓鱼. 睡觉.
- 【OpenOffice+swftools】在线预览环境的搭建和xpdf中文包的配置
[环境参数] Host:Win7 64bit VMware:VMware Workstation11.1.0 Client OS:CentOS release 6.5 (Final) 2.6.32-4 ...
- HDU 1712 ACboy needs your help (分组背包模版题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1712 有n门课,和m天时间.每门课上不同的天数有不同的价值,但是上过这门课后不能再上了,求m天里的最大 ...
- Objc基础学习记录3
在学习Objective-c中, 数组 1.NSArray, 这是一个不可变的数组,不能修改和删除其中的对象,可以存储任意objective的对象指针. 不能存储int,char类型的,,需要转换为需 ...
- C++ 类的静态成员详细讲解[转]
在C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用.所以在所有对象中都可以共享它.使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节 ...
- Mysql用户密码设置修改和权限分配
我的mysql安装在c:\mysql 一.更改密码 第一种方式: 1.更改之前root没有密码的情况 c:\mysql\bin>mysqladmin -u root password " ...
- CSS规则整理
一. 善用css缩写规则 /*注意上.右.下.左的书写顺序*/1. 关于边距(4边):1px 2px 3px 4px (上.右.下.左)1px 2px 3px (省略的左等于右)1px 2px (省略 ...
- 复选框输入Android Studio 如果修改LogCat的颜色,默认全是黑色看着挺不舒服的
今天一直在查找复选框输入之类的问题,上午正好有机会和大家分享一下. 怎么找到并表现LogCat这里就不需要再讲了吧,主要说一下本篇的主题,如何修改他的颜色 .我们在使用Eclipse的时候应该都用过L ...
- Educational Codeforces Round 4 A. The Text Splitting 水题
A. The Text Splitting 题目连接: http://www.codeforces.com/contest/612/problem/A Description You are give ...
- Bootstrap 教程
Bootstrap,来自 Twitter,是基于 HTML.CSS.JAVASCRIPT 的简介灵活的流行前段框架及交互组件集. 内容列表 Bootstrap 教程 Bootstrap 教程 Boot ...