1. 程式人生 > >Luogu P3834 【模板】可持久化線段樹 1(主席樹)

Luogu P3834 【模板】可持久化線段樹 1(主席樹)

while iostream 可持久化線段樹 const str stream con urn pac

就是板子、、、

節點中維護的值,就是1-i之間這個區間內出現了數的次數(權值線段樹?霧)。然後當我們查詢的時候,就是利用到了前綴和的思想,拿左端點那棵樹和右端點一減~

更新的時候需要新開的點就開,不需要的就連到原來的點上去,相當於更新一條鏈。這樣復雜度是nlogn的。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define R register int
#define ls (tr<<1)
#define rs (tr<<1|1)
using
namespace std; inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch==-?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } const int N=200010; int n,m,q,tot,T; int a[N],b[N]; int t[N],sum[N<<5],L[N<<5],Rr[N<<5
]; inline int build(int l,int r) { R tr=++tot,md=(l+r)>>1; sum[tr]=0; if(l<r) L[tr]=build(l,md),Rr[tr]=build(md+1,r); return tr; } inline int upd(int pre,int l,int r,int vl) { R tr=++tot; R md=(l+r)>>1; L[tr]=L[pre],Rr[tr]=Rr[pre],sum[tr]=sum[pre]+1; if
(l<r) { if(vl<md+1) L[tr]=upd(L[pre],l,md,vl); else Rr[tr]=upd(Rr[pre],md+1,r,vl); } return tr; } inline int query(int lst,int tr,int l,int r,int k) { if(l>=r) return l; R md=(l+r)>>1; R x=sum[L[tr]]-sum[L[lst]]; if(x>=k) return query(L[lst],L[tr],l,md,k); else return query(Rr[lst],Rr[tr],md+1,r,k-x); } signed main() { n=g(),q=g(); for(R i=1;i<=n;++i) a[i]=b[i]=g(); sort(b+1,b+n+1); R m=unique(b+1,b+n+1)-b-1; t[0]=build(1,m); for(R i=1;i<=n;++i) { a[i]=lower_bound(b+1,b+m+1,a[i])-b; t[i]=upd(t[i-1],1,m,a[i]); } while(q--) { R x=g(),y=g(),z=g(); R p=query(t[x-1],t[y],1,m,z); printf("%d\n",b[p]); } }

好想大佬們都把根作為實參轉進去。。我的碼風有待提高。。QAQ


2019.04.17

Luogu P3834 【模板】可持久化線段樹 1(主席樹)