靜態區間第k大 樹套樹解法
阿新 • • 發佈:2018-09-03
i++ val pri math 1+n std -a 平衡樹 scanf
然而過不去你谷的模板
思路:
值域線段樹\([l,r]\)代表一棵值域在\([l,r]\)範圍內的點構成的一顆平衡樹
平衡樹的\(BST\)權值為點在序列中的位置
查詢區間第\(k\)大值時
左區間在\([l,r]\)範圍內的樹的大小與\(k\)比較
大了進去,小了減掉換一邊
關於建樹
遞歸建估計是\(O(nlog^2n)\)的
Code:
#include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> const int N=1e5+10; int ch[N*20][2],val[N*20],siz[N*20],pos[N*20],root[N<<2],tot; #define ls ch[now][0] #define rs ch[now][1] int n,m,n_,a[N],b[N]; void updata(int now){siz[now]=siz[ls]+siz[rs]+1;} void split(int now,int k,int &x,int &y) { if(!now) {x=y=0;return;} if(pos[now]<=k) x=now,split(rs,k,rs,y); else y=now,split(ls,k,x,ls); updata(now); } int Merge(int x,int y) { if(!x||!y) return x+y; if(val[x]<val[y]) { ch[x][1]=Merge(ch[x][1],y); updata(x); return x; } else { ch[y][0]=Merge(x,ch[y][0]); updata(y); return y; } } int New(int k) { val[++tot]=rand(),pos[tot]=k,siz[tot]=1; return tot; } void Insert(int id,int k) { int x,y; split(root[id],k,x,y); root[id]=Merge(x,Merge(New(k),y)); } int ask(int id,int l,int r)//詢問區間 { int x,y,z,s; split(root[id],r,x,y); split(x,l-1,x,z); s=siz[z]; root[id]=Merge(x,Merge(z,y)); return s; } std::vector <int> loc[N]; void build(int id,int l,int r) { if(l==r) { for(int i=0;i<loc[l].size();i++) Insert(id,loc[l][i]); return; } int mid=l+r>>1; build(id<<1,l,mid); build(id<<1|1,mid+1,r); for(int i=l;i<=r;i++) for(int j=0;j<loc[i].size();j++) Insert(id,loc[i][j]); } int query(int id,int l,int r,int ql,int qr,int k) { if(l==r) return a[l]; int mid=l+r>>1,cnt; if((cnt=ask(id<<1,ql,qr))>=k) return query(id<<1,l,mid,ql,qr,k); else return query(id<<1|1,mid+1,r,ql,qr,k-cnt); } void init() { scanf("%d%d",&n_,&m); for(int i=1;i<=n_;i++) scanf("%d",a+i),b[i]=a[i]; std::sort(a+1,a+1+n_); n=std::unique(a+1,a+1+n_)-a-1; for(int i=1;i<=n_;i++) loc[std::lower_bound(a+1,a+1+n,b[i])-a].push_back(i); build(1,1,n); } void work() { for(int l,r,k,i=1;i<=m;i++) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",query(1,1,n,l,r,k)); } } int main() { init(),work(); return 0; }
2018.9.2
靜態區間第k大 樹套樹解法