询问区间第k大(小)——主席树
2015-08-13 07:47
295 查看
例题
K-th Number
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.
题目大意
给出一个序列a1,a2...an,有若干个询问,每个询问形如(l,r,k),询问l到r的第k大是多少
直观想法
我们可以用前缀和,建出n棵线段树,第i棵线段树涵盖了1~i区间的数的信息,每次的询问只需要用第r棵线段树的信息减去第l−1棵线段树的信息,然后直接查找就好了,伪代码如下:
然而,这样的时间与空间复杂度并不如人意,时间复杂度O(n2log2n),空间复杂度O(n2log2n),简直不如暴力。
怎么办?
主席树!!!
我们通过观察发现第i棵线段树与第i−1棵线段树不同的只有log2n个点的信息,于是我们可以只存下有有用信息的点,在建第i棵线段树时,借用第i−1棵线段树的与i棵线段树相同的信息,这就是主席树。
缺点
然而,这样建主席树的方法不可以支持修改操作,可修改的主席树将在后面的博客中讲。
下面附一下代码:
K-th Number
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.
题目大意
给出一个序列a1,a2...an,有若干个询问,每个询问形如(l,r,k),询问l到r的第k大是多少
直观想法
我们可以用前缀和,建出n棵线段树,第i棵线段树涵盖了1~i区间的数的信息,每次的询问只需要用第r棵线段树的信息减去第l−1棵线段树的信息,然后直接查找就好了,伪代码如下:
//离散化 i=1 -> n j=1 -> i-1 change(i,1,1,n,ask(a[j])); //ask()是用二分找出a[j]在离散化后的序列的位置
然而,这样的时间与空间复杂度并不如人意,时间复杂度O(n2log2n),空间复杂度O(n2log2n),简直不如暴力。
怎么办?
主席树!!!
我们通过观察发现第i棵线段树与第i−1棵线段树不同的只有log2n个点的信息,于是我们可以只存下有有用信息的点,在建第i棵线段树时,借用第i−1棵线段树的与i棵线段树相同的信息,这就是主席树。
缺点
然而,这样建主席树的方法不可以支持修改操作,可修改的主席树将在后面的博客中讲。
下面附一下代码:
#include<cstdio> #include<cstring> #include<algorithm> #define maxn 100005 #define maxm 1800005 #define lp left[p] #define lq left[q] #define rp right[p] #define rq right[q] #define sp sum[p] #define sq sum[q] #define fo(i,a,b) for(int i=a;i<=b;i++) using namespace std; int n,m,tot,left[maxm],right[maxm],sum[maxm],root[maxn],a[maxn],id[maxn],b[maxn]; bool cmp(int x,int y) { return a[x]<a[y]; } void add(int &p,int q,int l,int r,int v) { p=++tot; sp=sq+1; lp=lq; rp=rq; if (l==r) return; int mid=(l+r)/2; if (v<=mid) add(lp,lq,l,mid,v);else add(rp,rq,mid+1,r,v); } int query(int p,int q,int l,int r,int v) { if (l==r) return l; int mid=(l+r)/2; if (sum[lq]-sum[lp]>=v) return query(lp,lq,l,mid,v); return query(rp,rq,mid+1,r,v-sum[lq]+sum[lp]); } int main() { scanf("%d%d",&n,&m); fo(i,1,n) scanf("%d",&a[i]); fo(i,1,n) id[i]=i; sort(id+1,id+n+1,cmp); int size=1; fo(i,2,n) { if (a[id[i]]!=a[id[i-1]]) b[++size]=a[id[i]]; a[id[i]]=size; } b[1]=a[id[1]]; a[id[1]]=1; root[0]=0;tot=0; fo(i,1,n) add(root[i],root[i-1],1,size,a[i]); fo(i,1,m) { int l,r,k; scanf("%d%d%d",&l,&r,&k); printf("%d\n",b[query(root[l-1],root[r],1,size,k)]); } return 0; }
相关文章推荐
- 注册表的组织结构
- SQLSERVER的非聚集索引结构深度理解
- 调整SQLServer2000运行中数据库结构
- C#基础语法:结构和类区别详解
- 深入c# 类和结构的区别总结详解
- c#结构和类的相关介绍
- C#中结构(struct)的部分初始化和完全初始化实例分析
- C#中类与结构的区别实例分析
- C#枚举类型与结构类型实例解析
- javascript实现表现、结构、行为分离的选项卡效果!
- 实用的js 焦点图切换效果 结构行为相分离
- asp下生成目录树结构的类
- thinkphp文件引用与分支结构用法实例
- php实现的树形结构数据存取类实例
- Swift教程之类与结构详解
- 第三话:关于数据结构的一些概念
- 树形结构java代码以及结果
- Oracle Database 9i/10g/11g编程艺术
- 数据结构的基本概念和术语
- 硬盘结构及其分区简介