洛谷P3834 [模板]可持久化線段樹1(主席樹) [主席樹]
題目傳送門
可持久化線段樹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(主席樹) [主席樹]