前置芝士 P3369 【模板】普通平衡树
线段树套平衡树
这里写的是线段树+splay(不吸氧竟然卡过了)
对线段树的每个节点都维护一颗平衡树
每次把给定区间内
线段树上节点维护的平衡树的信息
查询一遍就好辣
$opt2$:每次二分一个答案k,蓝后用$opt1$跑,再判断偏大还是偏小
我真的要好好背背splay的各种神仙操作了TAT
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; inline int Max(int a,int b){return a>b?a:b;} inline int Min(int a,int b){return a<b?a:b;} void read(int &x){ static char c=getchar();x=0; while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar(); } #define N 50005 const int inf=2147483647; struct node{ int ch[2],siz,v,fa; void clear(){ch[0]=ch[1]=v=fa=siz=0;} }a[4000005]; int n,m,u,A[N]; queue <int> lit; int New(){ if(lit.empty()) return ++u; int p=lit.front(); lit.pop(); return p; } struct Splay{ #define lc a[x].ch[0] #define rc a[x].ch[1] int rt,re; inline void up(int x){a[x].siz=a[lc].siz+a[rc].siz+1;} inline int whi(int y,int x){return a[y].ch[1]==x;} void turn(int x,int &k){ int y=a[x].fa,z=a[y].fa,l=whi(y,x),r=l^1; if(y==k) k=x; else a[z].ch[whi(z,y)]=x; a[a[x].ch[r]].fa=y; a[y].fa=x; a[x].fa=z; a[y].ch[l]=a[x].ch[r]; a[x].ch[r]=y; up(y); up(x); } void splay(int x,int &k){ for(;x!=k;turn(x,k)){ int y=a[x].fa,z=a[y].fa; if(y!=k) turn((whi(z,y)^whi(y,x))?x:y,k); } } int find(int x,int k){ while(a[lc].siz+1!=k){ if(a[lc].siz+1>=k) x=lc; else k=k-a[lc].siz-1,x=rc; }return x; } int torank(int k){ int x=rt,re=0,id=0; while(x){ if(a[x].v==k) id=x; if(a[x].v>=k) x=lc; else re+=a[lc].siz+1,x=rc; }if(id) splay(id,rt);// return re; } void ins(int k){ int x=rt,Fa=0; while(x) Fa=x,x=a[x].ch[a[x].v<=k]; x=New(); a[x].v=k,a[x].fa=Fa; if(rt) a[Fa].ch[a[Fa].v<=k]=x,splay(x,rt); else rt=x; } void del(int k){ int x=rt,p,tmp; while(a[x].v!=k) x=a[x].ch[a[x].v<=k]; splay(x,rt); tmp=rt; if(lc&&rc){// p=find(rt,a[lc].siz); splay(p,lc),x=rt; a[lc].ch[1]=rc,a[rc].fa=lc; rt=lc,a[rt].fa=0,up(rt); }else if(lc) a[lc].fa=0,rt=lc; else if(rc) a[rc].fa=0,rt=rc; else rt=0; a[tmp].clear(); lit.push(tmp); } void Pre(int x,int k){ if(!x) return; if(re<a[x].v&&a[x].v<k) re=a[x].v; Pre(a[x].ch[a[x].v<k],k); } void Last(int x,int k){ if(!x) return ; if(k<a[x].v&&a[x].v<re) re=a[x].v; Last(a[x].ch[a[x].v<=k],k); } int pre(int k){re=-inf;Pre(rt,k);return re;} int last(int k){re=inf;Last(rt,k);return re;} #undef lc #undef rc }s[N<<2]; struct Seg_tree{ #define lc o<<1 #define rc o<<1|1 #define mid (l+r)/2 void Ins(int o,int l,int r,int x,int v){ s[o].ins(v); if(l==r) return ; if(x<=mid) Ins(lc,l,mid,x,v); else Ins(rc,mid+1,r,x,v); } int Ask1(int o,int l,int r,int x1,int x2,int v){ if(x1<=l&&r<=x2) return s[o].torank(v); int re=0; if(x1<=mid) re+=Ask1(lc,l,mid,x1,x2,v); if(x2>mid) re+=Ask1(rc,mid+1,r,x1,x2,v); return re; } void Modi(int o,int l,int r,int x,int v1,int v2){ s[o].del(v1); s[o].ins(v2); if(l==r) return ; if(x<=mid) Modi(lc,l,mid,x,v1,v2); else Modi(rc,mid+1,r,x,v1,v2); } int Ask4(int o,int l,int r,int x1,int x2,int v){ if(x1<=l&&r<=x2) return s[o].pre(v); int re=-inf; if(x1<=mid) re=Max(re,Ask4(lc,l,mid,x1,x2,v)); if(x2>mid) re=Max(re,Ask4(rc,mid+1,r,x1,x2,v)); return re; } int Ask5(int o,int l,int r,int x1,int x2,int v){ if(x1<=l&&r<=x2) return s[o].last(v); int re=inf; if(x1<=mid) re=Min(re,Ask5(lc,l,mid,x1,x2,v)); if(x2>mid) re=Min(re,Ask5(rc,mid+1,r,x1,x2,v)); return re; } #undef lc #undef rc #undef mid }T; int main(){ read(n);read(m); register int i; int q1,q2,q3,q4; for(i=1;i<=n;++i) read(A[i]),T.Ins(1,1,n,i,A[i]); while(m--){ read(q1);read(q2);read(q3); switch(q1){ case 1:{read(q4),printf("%d ",T.Ask1(1,1,n,q2,q3,q4)+1);break;}//排名要+1,算上自己 case 2:{ read(q4); int l=0,r=1e8; while(l<r){ //二分比较特殊,每次二分的mid要偏大一点 int mid=(l+r+1)/2; if(T.Ask1(1,1,n,q2,q3,mid)<q4) l=mid; else r=mid-1; }printf("%d ",l); break; } case 3:{T.Modi(1,1,n,q2,A[q2],q3),A[q2]=q3;break;} case 4:{read(q4),printf("%d ",T.Ask4(1,1,n,q2,q3,q4));break;} case 5:{read(q4),printf("%d ",T.Ask5(1,1,n,q2,q3,q4));break;} } }return 0; }