POJ2104-K-th Number(靜態主席樹模板 區間第k小)

題目鏈接

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


題意

給n個數,求區間 [ i , j ] 的第k小是多少

思路

主席樹思路的理解:https://blog.csdn.net/creatorx/article/details/75446472

主席樹的圖示:https://blog.csdn.net/a_forever_dream/article/details/80450549

求第k小值,是權值線段樹的作用,權值線段樹與線段樹區別是,保存的是數出現的次數

 

如果用sort排序,用前綴和的思想,只建立n棵權值線段樹。如果知道[1,l - 1 ] 和[1,r ]區間比k小的個數,相減就是[l,r]區間比k小的個數,因爲結點維護的區間範圍是一樣的

n棵線段樹空間複雜度O(n*n*logn),仍然太大,但是每次第i棵線段樹和第i+1棵線段樹的區別其實只有一條鏈不同,所以可用重複利用相同的部分,節省空間。

盜上面鏈接一張圖...

每次的根都是不一樣的,但是根都複製了前面根的左右子樹的編號,如果需要修改就再新建,不需要修改就複用之前的。

主席樹的建樹空間複雜度O(nlogn),建樹時間複雜度O(nlogn),訪問時間複雜度O(logn)。

線段樹空間複雜度O(n*4),時間複雜度一樣。

 

主席樹可以理解爲,多棵權值線段樹的空間優化。


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5+10;

struct Tree
{
    int l,r,sum;
}tr[N*20];

struct node
{
    int x,id;
}a[N];
bool cmp(node v1,node v2){return v1.x<v2.x;}

int rk[N],root[N],cnt;

void update(int &k,int l,int r,int v)
{
    tr[cnt] = tr[k]; tr[cnt].sum++;
    k = cnt++;
    if(l==r) return;
    int mid = (l+r)/2;
    if(v<=mid) update(tr[k].l,l,mid,v);
    else update(tr[k].r,mid+1,r,v);
}

int query(int L,int R,int l,int r,int k)
{

    if(l==r) return l;
    int d = tr[tr[R].l].sum - tr[tr[L].l].sum;
    int mid = (l+r)/2;
    if(k<=d) return query(tr[L].l,tr[R].l,l,mid,k);
    else return query(tr[L].r,tr[R].r,mid+1,r,k-d);
}

int main()
{
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i].x);
        a[i].id = i;
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++) rk[a[i].id] = i;

    cnt = 1;

    for(int i=1;i<=n;i++){
        root[i] = root[i-1];
        update(root[i],1,n,rk[i]);
    }

    for(int i=1;i<=m;i++){
        int x,y,v; scanf("%d%d%d",&x,&y,&v);
        int t = query(root[x-1],root[y],1,n,v);
        printf("%d\n",a[t]);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章