POJ 2104 K-th Number
Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 59481 | Accepted: 20727 | |
Case Time Limit: 2000MS |
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.
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).
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.
Source
主席树(函数式线段树)裸题
主席树是一种离线数据结构,是由很多棵线段树组成的。
第i棵树代表第i个数出现前的情况
每个线段存数字的出现次数
听起来
肯定会MLE !
但是我们发现i和i-1的某些节点完全相同 所以只需要借用以前的点就可以 ,不需要新建。
那么如果要询问i-j之间数字出现的次数怎么办呢?
因为每一棵线段树的区间都是相同的,所以要求l-r之间的数字的出现次数只要用前r位出现的次数减去前l-1位出现的次数,就是ans
但是如果有修改操作怎么办?
如果沿用上面的做法,那么修改操作是O(nlogn)的,查询是O(1)的,修改要花好长时间。。。
前缀和联想到了树状数组,那么将前缀和用树状数组维护的话修改是O(logn*logn),查询时O(logn),查询的时间虽然变长,但是修改的时间缩短许多!!
注意:
函数式线段树的数组要开大一点!!
转载自http://blog.csdn.net/regina8023/article/details/41910615
现在还不会主席树,先敲下模板,以后会用到的
本题没涉及到修改
#include <algorithm> #include <cstdio> #define N 105000 using std::sort; using std::unique; using std::lower_bound; struct cmt { int l,r,Size; }tr[N*20]; int a[N],b[N],t[N],tot,Size,n,m,T; int build(int l,int r) { int root=++tot; tr[root].Size=0; if(l==r) return root; int mid=(l+r)>>1; tr[root].l=build(l,mid); tr[root].r=build(mid+1,r); return root; } int update(int rt,int x) { int now=++tot; int tmp=now; tr[now].Size=tr[rt].Size+1; for(int mid,l=1,r=Size;l<=r;) { mid=(l+r)>>1; if(x<=mid) { tr[now].l=++tot; tr[now].r=tr[rt].r; rt=tr[rt].l; now=tot; r=mid-1; } else { tr[now].l=tr[rt].l; tr[now].r=++tot; rt=tr[rt].r; now=tot; l=mid+1; } tr[now].Size=tr[rt].Size+1; } return tmp; } int ask(int lx,int rx,int k) { int l=1,r=Size; for(int mid;l<=r;) { mid=(l+r)>>1; if(tr[tr[rx].l].Size-tr[tr[lx].l].Size>=k) { rx=tr[rx].l; lx=tr[lx].l; r=mid-1; } else { k-=tr[tr[rx].l].Size-tr[tr[lx].l].Size; rx=tr[rx].r; lx=tr[lx].r; l=mid+1; } } return l; } int main() { scanf("%d",&T); for(;T--;) { tot=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+1+n); Size=unique(b+1,b+1+n)-b-1; t[0]=build(1,Size); for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+Size,a[i])-b; for(int i=1;i<=n;++i) t[i]=update(t[i-1],a[i]); for(int x,y,k;m--;) { scanf("%d%d%d",&x,&y,&k); printf("%d\n",b[ask(t[x-1],t[y],k)]); } } return 0; }
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。