poj2104求區間第k小,靜態主席樹入門模板
阿新 • • 發佈:2018-11-25
看了很久的主席樹,最後看https://blog.csdn.net/williamsun0122/article/details/77871278這篇終於看懂了
#include <stdio.h> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 1e5+5; int T[maxn],L[maxn*20],R[maxn*20],sum[maxn*20]; //sz[]為原序列,h[]為去重化後序列 int sz[maxn],h[maxn]; int n,q,ql,qr,k,tot; void build(int& rt,int l,int r) //建空樹 { rt = ++tot; sum[rt] = 0;//在該區間的元素個數 if(l==r) return; int mid = (l+r)>>1; build(L[rt],l,mid); build(R[rt],mid+1,r); } //對所有字首更新樹 void update(int& rt,int l,int r,int pre,int x) { rt = ++tot; L[rt]=L[pre]; R[rt]=R[pre];//新樹繼承上一個樹,並在其中加入一個新元素 sum[rt] = sum[pre]+1;//元素個數加一 if(l==r) return; int mid = (l+r)>>1; if(x<=mid) update(L[rt],l,mid,L[pre],x); else update(R[rt],mid+1,r,R[pre],x); } int query(int s,int e,int l,int r,int k) { if(l==r) return l; int mid = (l+r)>>1; int res = sum[L[e]]-sum[L[s]]; //同時求左子樹的個數相減,可以看做是一顆以[l.r]建立的線段樹的左子樹的元素的個數 if(k<=res) return query(L[s],L[e],l,mid,k); else return query(R[s],R[e],mid+1,r,k-res); } int main() { // int t; // scanf("%d",&t); // while(t--) // { scanf("%d%d",&n,&q); for(int i=1; i<=n; i++) scanf("%d",sz+i),h[i]=sz[i]; sort(h+1,h+1+n); int num = unique(h+1,h+1+n)-h-1;//去重後求剩餘元素個數 tot=0; build(T[0],1,num);//初始化 for(int i=1; i<=n; i++) { //離散化後更新 int x=lower_bound(h+1,h+1+num,sz[i])-h;//求出當前元素的離散後值,從1開始所以是減h update(T[i],1,num,T[i-1],x); } while(q--) { scanf("%d%d%d",&ql,&qr,&k); int ans = query(T[ql-1],T[qr],1,num,k); printf("%d\n",h[ans]);//離散後的答案對應原去重後的下標 } // } return 0; }