P3834 【模板】可持久化线段树 1(主席树)
板子。。。。
题意:给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。
这个空间。。50倍。。。。
每次新开节点,与原来节点公用左右儿子(随便认儿子,然后在更新维护)
#include<cstdio> #include<iostream> #include<cctype> #include<algorithm> using namespace std; #define nmr 205050 #define olinr return #define love_nmr 0 int n; int m; int p; int len; int cnt; int rt[nmr]; int ls[nmr<<5]; int rs[nmr<<5]; int num[nmr<<5]; int a[nmr]; int b[nmr]; inline int read() { char ch=getchar(); int f=1,x=0; while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { putchar('-'); x=-x; } if(x>9) put(x/10); putchar(x%10+'0'); } inline void build(int &o,int l,int r) { o=++cnt; if(l==r) olinr; int mid=(l+r)>>1; build(ls[o],l,mid); build(rs[o],mid+1,r); } inline int add(int o,int l,int r) { int root=++cnt; ls[root]=ls[o]; rs[root]=rs[o]; num[root]=num[o]+1; if(l==r) olinr root; int mid=(l+r)>>1; if(p<=mid) ls[root]=add(ls[root],l,mid); if(p>mid) rs[root]=add(rs[root],mid+1,r); olinr root; } inline int query(int l,int r,int x,int y,int k) { int ans=0; int pos=num[ls[y]]-num[ls[x]]; if(l==r) olinr l; int mid=(l+r)>>1; if(k<=pos) ans=query(l,mid,ls[x],ls[y],k); if(k>pos) ans=query(mid+1,r,rs[x],rs[y],k-pos); return ans; } int main() { n=read(); m=read(); for(int i=1;i<=n;i++) b[i]=a[i]=read(); sort(b+1,b+n+1); len=unique(b+1,b+n+1)-b-1; build(rt[0],1,len); for(int i=1;i<=n;i++) { p=lower_bound(b+1,b+len+1,a[i])-b; rt[i]=add(rt[i-1],1,len); } while(m--) { int l=read(); int r=read(); int k=read(); put(b[query(1,len,rt[l-1],rt[r],k)]); putchar('\n'); } olinr love_nmr; }
----olinr