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. ListCell Animation in ListView

    After a long time I am back again with new stuffs. I have seen that JavaFX has got so many demand no ...

  2. HD1085 Holding Bin-Laden Captive!

    Problem Description We all know that Bin-Laden is a notorious terrorist, and he has disappeared for ...

  3. C#下载http文件

    @(编程) using System; using System.IO; using System.Net; namespace Wisdombud.Util { public class HttpH ...

  4. 未能加载文件或程序集“Oracle.DataAccess, Version=2.112.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342”或它的某一个依赖项。 解决方法

    webconfig文件对于oracle的映射错误.需要在以下位置修改 <runtime> <legacyCorruptedStateExceptionsPolicy enabled= ...

  5. c# 调用zebra打印指令 打印到USB端口

    c# 调用zebra打印机指令打印条码,如果直接打印到lpt1端口的打印机,通过copy指令没有问题, 但如果ZEBRA打印机是通过USB连接,打印机端口为usb001,则程序不能直接拷贝到usb00 ...

  6. C#图解教程读书笔记(第1章 C#和.net框架)

    C#中的主要需要记住的基础概念 CLR公共语言运行库 CIL中间语言,所有的代码都会编译成中间语言. CLI公共语言基础结构 C#的优点 C#有自动垃圾回收机制

  7. c++字符串机理

    在windows编程中,由于编码方式的不同和c与c++的不同而造成了许多复杂的有关字符串之间的转换 首先,windows编码方式有ANSCLL和UNICODE,前者是单字符的,后者是双字符的. 然后, ...

  8. M站 confirm 插件

    /*弹出提示*/.pop-error{position:absolute; left:25%; top:50%; width:200px; FILTER: progid:DXImageTransfor ...

  9. java_web用户的自动登录模块的实现

    javaBean的代码 package bean; import java.io.Serializable; public class Admin implements Serializable{ / ...

  10. chrome浏览器下用jQuery的load函数来跨域加载页面,响应状态status为(canceled)是什么情况? JSON和JSONP,也许你会豁然开朗,含jQuery用例

    http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html 问题来源:http://q.cnblogs.com ...