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 线段树(归并树)+二分查找的更多相关文章

  1. HDU-4614 Vases and Flowers(线段树区间更新+二分查找)

    http://acm.hdu.edu.cn/showproblem.php?pid=4614 Time Limit: 4000/2000 MS (Java/Others)    Memory Limi ...

  2. 线段树离散化 unique + 二分查找 模板 (转载)

    离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率. 通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小.例如: 原数据:1,999,100000,15:处理 ...

  3. 洛谷P4332 [SHOI2014]三叉神经树(LCT,树剖,二分查找,拓扑排序)

    洛谷题目传送门 你谷无题解于是来补一发 随便百度题解,发现了不少诸如树剖\(log^3\)LCT\(log^2\)的可怕描述...... 于是来想想怎么利用题目的性质,把复杂度降下来. 首先,每个点的 ...

  4. POJ 2182 Lost Cows (树状数组 && 二分查找)

    题意:给出数n, 代表有多少头牛, 这些牛的编号为1~n, 再给出含有n-1个数的序列, 每个序列的数 ai 代表前面还有多少头比 ai 编号要小的牛, 叫你根据上述信息还原出原始的牛的编号序列 分析 ...

  5. PAT-1057 Stack (树状数组 + 二分查找)

    1057. Stack Stack is one of the most fundamental data structures, which is based on the principle of ...

  6. 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 ...

  7. (经典) K&R的名著<<C程序设计语言>>二分查找

    #include<stdio.h> //查找成功则返回所在下标否则返回-1 int binsearch(int A[], int n,int a) { int low, high, mid ...

  8. toj 4353 Estimation(树状数组+二分查找)

    Estimation 时间限制(普通/Java):5000MS/15000MS     运行内存限制:65536KByte总提交: 6            测试通过: 1 描述 “There are ...

  9. 树状数组+二分||线段树 HDOJ 5493 Queue

    题目传送门 题意:已知每个人的独一无二的身高以及排在他前面或者后面比他高的人数,问身高字典序最小的排法 分析:首先对身高从矮到高排序,那么可以知道每个人有多少人的身高比他高,那么取较小值(k[i], ...

  10. 离散化+线段树/二分查找/尺取法 HDOJ 4325 Flowers

    题目传送门 题意:给出一些花开花落的时间,问某个时间花开的有几朵 分析:这题有好几种做法,正解应该是离散化坐标后用线段树成端更新和单点询问.还有排序后二分查找询问点之前总花开数和总花凋谢数,作差是当前 ...

随机推荐

  1. 如何使cron任务出错时发邮件

    如果设置了 MAILTO,cron就会将任务的标准输出和标准错误输出重定向到邮箱(即发送邮件).但如果只想接到错误报警邮件 -- 即任务正常执行时不发送,只在出错时发送 -- 应该怎么实现呢? 方法很 ...

  2. Objective-C 学习笔记(1)

    文件描述: .h 类的声明文件,用户声明变量.函数(方法) .m 类的实现文件,用户实现.h中的函数(方法) 类的声明使用关键字 @interface.@end 类的实现使用关键字@implement ...

  3. Database事件研究

    1.Database.ObjectAppended.ObjectModified.ObjectErased事件 此事件如果不是Transaction提交而触发的,那么可以在事件内部使用Transact ...

  4. XML文件的生成与读取

    从数据库生成: public static void ToXML(string tablename) { //获取数据 string sql = "select * from " ...

  5. web.xml filter 顺序

    The order the container uses in building the chain of filters to be applied for a particular request ...

  6. 修改IIS7中ASP的上传文件大小限制

    最近在处理一个ASP的项目,用的全新的Windows Server 2008服务器. 今天客户反映图片文件上传不上去,设置服务器端文件夹权限之后文件可以上传了. 但是不久客户就反映有几个文件传不上去, ...

  7. How to log in to Amazon EC2 using PEM format from SecureCRT

    SecureCRT requires both a private and a public key. Use the supplied key.pem file from EC2 here as y ...

  8. Hadoop on Mac with IntelliJ IDEA - 9 解决Type mismatch in value from map问题

    修改陆喜恒. Hadoop实战(第2版)5.3排序的代码时遇到IO异常. 环境:Mac OS X 10.9.5, IntelliJ IDEA 13.1.5, Hadoop 1.2.1 异常具体信息如下 ...

  9. [ACM] hdu 1181 变形课

    变形课 Problem Description 呃......变形课上Harry碰到了一点小麻烦,由于他并不像Hermione那样可以记住全部的咒语而任意的将一个棒球变成刺猬什么的,可是他发现了变形咒 ...

  10. Android入门——电话拨号器和四种点击事件

    相对于HelloWorld来说,电话拨号器也是Android的一个入门demo,从这个样例我们要理清楚做安卓项目的思路. 大体分为三步: 1.理解需求,理清思路 2.设计UI 3.代码实现 电话拨号器 ...