POJ 2104 K-th Number 靜態第K大模板

題目鏈接:POJ 2104

K-th Number
Time Limit: 20000MS   Memory Limit: 65536K
Total Submissions: 59422   Accepted: 20698
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. 

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.

題意:給出一個序列,求L,R中第K大數。
題目分析:靜態第k大的主席樹模板,主席樹本質上是可持久化的線段樹的結構,首先把原序列排序後按每棵線段樹保存前綴[1,i]來構建一棵空的線段樹,之後按原序列挨個插入,每插入一個數都相當於新建一棵線段樹。在第i棵線段樹的每個節點保存原序列[1,i]出現在節點代表區間的個數。每棵線段樹的結構是一樣的,這樣在查詢L,R的第k大時只需2棵線段樹R,L-1相減,代表同一區間的2節點相減代表原序列[L,R]在出現在當前區間有多少個元素,之後logn查詢即可。
我理解的主席樹就是支持加減的一堆結構完全相同的線段樹,同時每次插入一個點構成的新的一棵線段樹和前面的那棵只有一條路徑不同,所以把每次只添加這一條路徑就可以大大減少區間消耗。
//
//  main.cpp
//  POJ 2104 K-th Number
//
//  Created by teddywang on 2017/09/07.
//  Copyright © 2017年 teddywang. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct Node{
    int a,b,rs,ls,sum;
}tr[2000010];
int a[100010];
int rt[100010],pos,cnt;
struct node{
    int id;
    int num;
    friend bool operator < (node a,node b)
    {
        return a.num<b.num;
    }
}b[100010];
int ranks[100010];
void Build(int &node,int l,int r)
{
    node=++cnt;
    tr[node].a=l;
    tr[node].b=r;
    if(l==r)return;
    int mid=(l+r)>>1;
    Build(tr[node].ls,l,mid);
    Build(tr[node].rs,mid+1,r);
}

void Insert(int pre,int &node)
{
    node=++cnt;
    tr[node].ls=tr[pre].ls;
    tr[node].rs=tr[pre].rs;
    tr[node].a=tr[pre].a;
    tr[node].b=tr[pre].b;
    tr[node].sum=tr[pre].sum+1;
    if(tr[node].a==tr[node].b)return;
    int mid=(tr[node].a+tr[node].b)>>1;
    if(mid>=pos)Insert(tr[pre].ls,tr[node].ls);
    else Insert(tr[pre].rs,tr[node].rs);
}
int Query(int pre,int node,int k)
{
    if(tr[node].ls==tr[node].rs)return b[tr[node].a].num;
    int cmp=tr[tr[node].ls].sum-tr[tr[pre].ls].sum;
    if(cmp>=k)return Query(tr[pre].ls,tr[node].ls,k);
    else return Query(tr[pre].rs,tr[node].rs,k-cmp);
}
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;b[i].num=a[i],i++)
    {
        scanf("%d",&a[i]);
        b[i].id=i;
    }
    sort(b+1,b+n+1);
    for(int i=1;i<=n;i++)
    {
        ranks[b[i].id]=i;
    }
    Build(rt[0],1,n);
    for(int i=1;i<=n;i++)
    {
        pos=ranks[i];
        Insert(rt[i-1],rt[i]);
        
    }
    int l,r,k;
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",Query(rt[l-1],rt[r],k));
    }
    return 0;
}



發佈了168 篇原創文章 · 獲贊 4 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章