K-th Number POJ - 2104 主席树

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 10  9 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.


题意是查询区间(l,r)中第k小的数。可以用主席树在线查询。需要离散化。

查询的时候要用到第l-1颗树和第r颗树。这里两棵树的左右区间都是1-n,存的都是离散化后的值的数量。

那么第l-1颗树的右子树表示的就是前l-1个树中值落在(m+1,r)中的数量。

第r颗树的右子树表示的就是前r个树中值落在(m+1,r)中的数量

他们的值作差就表示第l-r个数中落在(m+1,r)中的数量,所以如果这个值大于等于k就继续往他们的右子树查询,第k大的数肯定在右子树里。

如果小于k,就说明在他们的左子树里这时k要减去前面那个值。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
map <int,int> mp;
int lala[maxn];
struct node1
{
    int v,pos;
}a[maxn],x[maxn];
int cmp(node1 a,node1 b)
{
    return a.v<b.v;
}
int cmp1(node1 a,node1 b)
{
    return a.pos<b.pos;
}
struct node
{
    int l,r;
    int v;
}tree[maxn*40];
int t[maxn];
int tot;
int build(int l,int r)
{
    int ii=tot++;
    tree[ii].v=0;
    if(l<r)
    {
        int m=(l+r)>>1;
        tree[ii].l=build(l,m);
        tree[ii].r=build(m+1,r);
    }
    return ii;
}
int update(int now,int l,int r,int x,int y)
{
    int ii=tot++;
    tree[ii].v=tree[now].v+y;
    tree[ii].l=tree[now].l;
    tree[ii].r=tree[now].r;
    if(l<r)
    {
        int mid=(l+r)>>1;
        if(x<=mid)tree[ii].l=update(tree[now].l,l,mid,x,y);
        else tree[ii].r=update(tree[now].r,mid+1,r,x,y);
    }
    return ii;
}
int finds(int l,int r,int x,int y,int k)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    int tmp=tree[tree[y].r].v-tree[tree[x].r].v;                     
    if(tmp>=k)return finds(mid+1,r,tree[x].r,tree[y].r,k);
    else return finds(l,mid,tree[x].l,tree[y].l,k-tmp);
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i].v),a[i].pos=i;
        int z=1;
        sort(a+1,a+n+1,cmp);
        x[z].v=1;x[z].pos=a[1].pos;
        tot=0;
        mp.clear();
        for(int i=2;i<=n;i++)
        {
            if(a[i].v==a[i-1].v)
               x[++z].v=x[z-1].v;
            else
                x[++z].v=x[z-1].v+1;
                x[z].pos=a[i].pos;
        }
        sort(x+1,x+1+n,cmp1);
        sort(a+1,a+1+n,cmp1);
        for(int i=1;i<=n;i++)
        {
            lala[x[i].v]=a[i].v;
        }
        t[0]=build(1,n);
       for(int i=1;i<=n;i++)
       {
            t[i]=update(t[i-1],1,n,x[i].v,1);

       }
       while(m--)
       {
           int l,r,k;
           scanf("%d%d%d",&l,&r,&k);
           printf("%d\n",lala[finds(1,n,t[l-1],t[r],r-l-k+2)]);
       }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/mayuqing98/article/details/79137297