【POJ2104】【HDU2665】K-th Number

Description

You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment. 
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?" 
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.

Input

The first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000). 
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given. 
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).

Output

For each question output the answer to it --- the k-th number in sorted a[i...j] segment.

Sample Input

7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

Sample Output

5
6
3

Hint

This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.
题意:n个数,m次询问,每次求区间[l,r]中的第k小的数
题解:主席树模板(什么是主席树?)
主席树也叫可持久化线段树、函数式线段树,我感觉就跟动态开点线段树差不多(什么是动态开点线段树?)
正常的线段树就是lson=x<<1,rson=x<<1|1,但动态开点线段树不同,它的节点的左右儿子是即用即开的,并用数组记录,每搜到一个点,如果以前没开过,就新开一个点,然后继续搜。这样我们就可以将多个线段树放到一起(怎么做?)
如果许多互部重叠线段树都建在[1,n]这个区间上,那么我们就可以直接将他们都放到一起,分别记录每棵线段树的根root[i],然后正常的在线段树上搞,当需要用到一段没开过的区间时,就新开一个点记录这个区间,然后继续向下查询,如果需要就在开新的点。这样我们可以对每棵线段树进行操作,空间复杂度O(nlogn)
好了,下面说主席树,主席树当然也要动态开点,建n棵线段树(都是权值线段树),不过第i棵线段树保存的是[1,i]这段区间,也就相当于一个前缀(那空间复杂度岂不是O(n^2)?)
于是我们发现,这一堆线段树其实有很大一部分是重复的,比如第i棵线段树,它相当于第i-1棵线段树中新开了一个点a[i],那么如果a[i]在[1,mid]这段区间里,那么第i棵线段树和第i-1课线段树的[mid+1,r]这段区间就是完全相同的!于是我们直接让他们共用这段区间即可(方法:把root[i]的右儿子指针指到root[i-1]的右儿子上,仅新建一个root[i]的左儿子)。同理,如果a[i]在[mid+1,r]这段区间里,我们就让他们共用左儿子,然后继续这样做,直到l==r。于是空间复杂度:O(nlogn)
那查询的时候该怎么做呢,对于本题,[l,r]中的第k小,那么我们已经处理出了[1,r]和[1,l-1]这两棵线段树,那么我们将这两棵线段树相减(因为是权值线段树,所以将每个点都相减即可),就相当于得到了一棵新的线段树[l,r],然后再求整体的第k小(这就很简单了吧)
上面说的这些也不算详解吧,其实就是我个人对主席树的一些理解罢了。
注意:可能有负数
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100010;
struct node
{
int ls,rs,siz;
}s[4000010];
struct NUM
{
int num,org;
}v[maxn];
int n,m,tot,nm;
int root[maxn],ref[maxn];
bool cmp1(NUM a,NUM b)
{
return a.num<b.num;
}
bool cmp2(NUM a,NUM b)
{
return a.org<b.org;
}
int readin()
{
int ret=0,f=1; char gc;
while(gc<'0'||gc>'9') {if(gc=='-')f=-f;gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void pushup(int x)
{
s[x].siz=s[s[x].ls].siz+s[s[x].rs].siz;
}
void insert(int &x,int &y,int l,int r,int p)
{
y=++tot;
if(l==r)
{
s[y].siz=s[x].siz+1;
return ;
}
int mid=l+r>>1;
if(p<=mid) s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,p);
else s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,p);
pushup(y);
}
int query(int x,int y,int l,int r,int p)
{
if(l==r) return ref[l];
int mid=l+r>>1;
if(s[s[y].ls].siz-s[s[x].ls].siz>=p) return query(s[x].ls,s[y].ls,l,mid,p);
return query(s[x].rs,s[y].rs,mid+1,r,p-s[s[y].ls].siz+s[s[x].ls].siz);
}
int main()
{
n=readin(),m=readin();
int i,a,b,c;
for(i=1;i<=n;i++) v[i].num=readin(),v[i].org=i;
sort(v+1,v+n+1,cmp1);
ref[0]=-1<<30;
for(i=1;i<=n;i++)
{
if(v[i].num>ref[nm]) ref[++nm]=v[i].num;
v[i].num=nm;
}
sort(v+1,v+n+1,cmp2);
for(i=1;i<=n;i++)
insert(root[i-1],root[i],1,nm,v[i].num);
for(i=1;i<=m;i++)
{
a=readin(),b=readin(),c=readin();
printf("%d\n",query(root[a-1],root[b],1,nm,c));
}
return 0;
}

最新文章

  1. 20145205 《Java程序设计》实验报告五:Java网络编程及安全
  2. 远程通知中app更新提示。
  3. Javascript日期比较
  4. Auto CAD 2013的故障解决方法
  5. c++各种数据类型表示范围
  6. POI 读取Excel文档中的数据——兼容Excel2003和Excel2007
  7. javascript 通过面向对象编写圆形数字时钟
  8. 【转】蓝牙4.0——Android BLE开发官方文档翻译
  9. SpringMVC与Struts2配置区别
  10. MapReduce 多表连接
  11. map中结构体做关键字的注意事项
  12. offsetof的意义
  13. VueJs(13)---过滤器
  14. MRP设置自动执行
  15. eclipse 等号左边代码补全
  16. xcode工程编译错误:The maximum number of apps for free development profiles has been reached.
  17. es6中export和export default的区别
  18. linux 基础命令使用
  19. MIT Molecular Biology 笔记6 转录的调控
  20. 本地项目通过github客户端上传到github网站上

热门文章

  1. Android中布局文件中使用onClick属性
  2. java socket网络编程(多线程技术)
  3. java 强弱引用
  4. IDL 计算TVDI
  5. Java 多态,重载,重写
  6. 使用Java的BlockingQueue实现生产者-消费者
  7. css伪类 伪元素
  8. 查看光纤卡wwn号【转载】
  9. Ubuntu将新增磁盘挂载到home下
  10. iOS中FMDB和GCD剖析