1. 程式人生 > >洛谷P3834 [模板]可持久化線段樹1(主席樹) [主席樹]

洛谷P3834 [模板]可持久化線段樹1(主席樹) [主席樹]

resid include tom c++ -a using printf getc int

  題目傳送門

可持久化線段樹1(主席樹)

題目背景

這是個非常經典的主席樹入門題——靜態區間第K小

數據已經過加強,請使用主席樹。同時請註意常數優化

題目描述

如題,給定N個正整數構成的序列,將對於指定的閉區間查詢其區間內的第K小值。

輸入輸出格式

輸入格式:

第一行包含兩個正整數N、M,分別表示序列的長度和查詢的個數。

第二行包含N個正整數,表示這個序列各項的數字。

接下來M行每行包含三個整數 $l,r,k$ , 表示查詢區間 $[l,r]$ 內的第k小值。

輸出格式:

輸出包含k行,每行1個正整數,依次表示每一次查詢的結果

輸入輸出樣例

輸入樣例#1:
5 5
25957 6405 15770 26287 26465 
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
輸出樣例#1:
6405
15770
26287
25957
26287

說明

數據範圍:

對於20%的數據滿足: $1 \leq N, M \leq 10$

對於50%的數據滿足: $1 \leq N, M \leq 10^3$

對於80%的數據滿足: $1 \leq N, M \leq 10^5$

對於100%的數據滿足: $1 \leq N, M \leq 2\cdot 10^5$

對於數列中的所有數 $a_i$? ,均滿足 $-{10}^9 \leq a_i \leq {10}^9$

樣例數據說明:

N=5,數列長度為5,數列從第一項開始依次為 $[25957,6405,15770,26287,26465]$


第一次查詢為 $[2,2]$ 區間內的第一小值,即為6405

第二次查詢為 $[3,4]$ 區間內的第一小值,即為15770

第三次查詢為 $[4,5]$ 區間內的第一小值,即為26287

第四次查詢為 $[1,2]$ 區間內的第二小值,即為25957

第五次查詢為 $[4,4]$ 區間內的第一小值,即為26287


  分析:

  主席樹入門題。

  一直說要學習主席樹來的,但是直到今天才實現。具體思想蒟蒻也就不贅述,貼一波布雷芙$\cdot$卡托爾學姐(誤)的博客。

  Code:

//It is made by HolseLee on 29th July 2018
//Luogu.org P3834
#include<bits/stdc++.h>
using namespace std;

const int N=2e5+7;
int n,m,tot,cnt,a[N],b[N],rk[N],rt[N];
struct President_tree{
    int ls,rs,sum;
}t[N*20];

int read()
{
    char ch=getchar();int num=0;bool flag=false;
    while(ch<0||ch>9){if(ch==-)flag=true;ch=getchar();}
    while(ch>=0&&ch<=9){num=(num<<3)+(num<<1)+ch-0;ch=getchar();}
    return flag?-num:num;
}

inline void build(int l,int r,int &node)
{
    node=++cnt; 
    if(l==r)return ;
    int mid=(l+r)>>1;
    build(l,mid,t[node].ls);
    build(mid+1,r,t[node].rs);
}

inline void update(int l,int r,int &node,int last,int tar)
{
    node=++cnt;t[node]=t[last];++t[node].sum;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(tar<=mid)update(l,mid,t[node].ls,t[last].ls,tar);
    else update(mid+1,r,t[node].rs,t[last].rs,tar);
}

inline int quary(int l,int r,int node,int last,int tar)
{
    if(l==r)return a[l];
    int now=t[t[node].ls].sum-t[t[last].ls].sum,mid=(l+r)>>1;
    if(tar<=now)return quary(l,mid,t[node].ls,t[last].ls,tar);
    else return quary(mid+1,r,t[node].rs,t[last].rs,tar-now);
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i){
        a[i]=read();b[i]=a[i];   
    }
    sort(a+1,a+n+1);
    tot=unique(a+1,a+n+1)-a-1;
    build(1,tot,rt[0]);
    for(int i=1;i<=n;++i)
        rk[i]=lower_bound(a+1,a+tot+1,b[i])-a;
    for(int i=1;i<=n;i++)
        update(1,tot,rt[i],rt[i-1],rk[i]);
    int l,r,k;
    for(int i=1;i<=m;++i){
        l=read();r=read();k=read();
        printf("%d\n",quary(1,tot,rt[r],rt[l-1],k));
    }
    return 0;
}

洛谷P3834 [模板]可持久化線段樹1(主席樹) [主席樹]