【Luogu】P3380树套树模板(线段树套Splay)
幸甚至哉,歌以咏志。
拿下了曾经是那么遥不可及的线段树,学会了曾经高不可攀的平衡树,弄懂了装B的时候才挂在嘴边的树套树。
每道模板都是链上的一颗珠子。把它们挨个串起来,就成为我成长的历程。
抒情结束开始讲题
这道题我们用线段树存平衡树的根节点。比如我们有一棵线段树
这样子。线段树的一个节点 存 它表示的那个区间 所对应的 平衡树 的根节点编号。这样每个节点都拥有一棵平衡树。是不是很炫呢?
对于操作1我们就可以把所有零散的区间里比它小的数的个数都找出来,+1就是答案啦。
对于操作2我们可以二分数,然后不断地进行操作1.
对于操作3我们用logn的时间把所有包含这个点的区间都修改一遍。
对于操作4和操作5,不多讲了。
很炫吧
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cctype> #define mid ((l+r)>>1) #define left (rt<<1) #define right (rt<<1|1) #define lson l,mid,left #define rson mid+1,r,right using std::max; using std::min; inline int read(){ int num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int s[502000]; int q[102000]; struct Node{ int e[2],fa,val,size,sum; }tree[5002000]; int tot,point; inline void update(int x){ tree[x].size=tree[x].sum; if(tree[x].e[0]) tree[x].size+=tree[tree[x].e[0]].size; if(tree[x].e[1]) tree[x].size+=tree[tree[x].e[1]].size; } inline void connect(int x,int fa,int how){ tree[x].fa=fa; tree[fa].e[how]=x; } inline int iden(int x){ return x==tree[tree[x].fa].e[1]; } void rotate(int x,int rt){ int y=tree[x].fa; int r=tree[y].fa; if(y==s[rt]) s[rt]=x; int sony=iden(x); int sonr=iden(y); int b=tree[x].e[sony^1]; connect(b,y,sony); connect(y,x,sony^1); connect(x,r,sonr); update(y); update(x); } void splay(int pos,int to,int rt){ to=tree[to].fa; while(tree[pos].fa!=to){ if(tree[tree[pos].fa].fa==to) rotate(pos,rt); else if(iden(pos)==iden(tree[pos].fa)){ rotate(tree[pos].fa,rt); rotate(pos,rt); } else { rotate(pos,rt); rotate(pos,rt); } } } inline int create(int val,int fa){ tree[++tot].val=val; tree[tot].fa=fa; tree[tot].sum=tree[tot].size=1; return tot; } inline void Delete(int x){ tree[x].e[0]=tree[x].e[1]=0; if(x==tot) tot--; } int build(int val,int rt){ point++; if(!s[rt]){ s[rt]=create(val,0); return s[rt];} else{ int now=s[rt]; while(1){ tree[now].size++; if(val==tree[now].val){ tree[now].sum++; return now; } int nxt=val<tree[now].val?0:1; if(!tree[now].e[nxt]){ create(val,now); tree[now].e[nxt]=tot; return tot; } now=tree[now].e[nxt]; } } return 0; } inline void insert(int val,int rt){ int p=build(val,rt); splay(p,s[rt],rt); } int find(int val,int rt){ int now=s[rt]; while(now){ if(tree[now].val==val){ splay(now,s[rt],rt); return now; } int nxt=val>tree[now].val; if(!tree[now].e[nxt]) return 0; now=tree[now].e[nxt]; } } void pop(int val,int rt){ int deal=find(val,rt); if(!deal) return; point--; if(tree[deal].sum>1){ tree[deal].sum--; tree[deal].size--; return; } if(!tree[deal].e[0]){ s[rt]=tree[deal].e[1]; tree[s[rt]].fa=0; } else{ int le=tree[deal].e[0]; while(tree[le].e[1]) le=tree[le].e[1]; splay(le,tree[deal].e[0],rt); int ri=tree[deal].e[1]; connect(ri,le,1); s[rt]=le; update(le); } Delete(deal); } int rank(int val,int rt){ int ans=0,now=s[rt]; while(1){ //printf("%d %d\n",now,tree[now].sum); if(val<tree[now].val){ now=tree[now].e[0]; if(!now) return ans; } else{ if(tree[now].e[0]) ans+=tree[tree[now].e[0]].size; if(val==tree[now].val||!tree[now].e[1]){ if(val>tree[now].val) ans+=tree[now].sum; splay(now,s[rt],rt); return ans; } ans+=tree[now].sum; now=tree[now].e[1]; } } } inline int lower(int val,int rt){ int ans=-2147483647,now=s[rt]; while(1){ if(!now) return ans; if(tree[now].val<val&&tree[now].val>ans) ans=tree[now].val; int nxt=val>tree[now].val?1:0; now=tree[now].e[nxt]; } } inline int upper(int val,int rt){ int ans=2147483647,now=s[rt]; while(1){ if(!now) return ans; if(tree[now].val>val&&tree[now].val<ans) ans=tree[now].val; int nxt=val>tree[now].val?1:0; now=tree[now].e[nxt]; } } int lows(int val,int rt){ int ans=-2147483647,now=s[rt]; while(1){ if(!now) return ans; if(tree[now].val<=val&&tree[now].val>ans) ans=tree[now].val; if(tree[now].val==val) return ans; int nxt=val>tree[now].val?1:0; now=tree[now].e[nxt]; } } void Build(int l,int r,int rt){ if(l>r) return; if(l==r){ insert(q[l],rt); return; } Build(lson); Build(rson); for(int i=l;i<=r;++i) insert(q[i],rt); return; } int findrank(int from,int to,int num,int l,int r,int rt){ if(from<=l&&to>=r) return rank(num,rt); int ans=0; if(from<=mid) ans+=findrank(from,to,num,lson); if(to>mid) ans+=findrank(from,to,num,rson); return ans; } void Update(int o,int num,int l,int r,int rt){ pop(q[o],rt); insert(num,rt); if(l==r) return; if(o<=mid) Update(o,num,lson); else Update(o,num,rson); } int findlower(int from,int to,int num,int l,int r,int rt){ if(from<=l&&to>=r) return lower(num,rt); int ans=-2147483647; if(from<=mid) ans=max(ans,findlower(from,to,num,lson)); if(to>mid) ans=max(ans,findlower(from,to,num,rson)); return ans; } int findupper(int from,int to,int num,int l,int r,int rt){ if(from<=l&&to>=r) return upper(num,rt); int ans=2147483647; if(from<=mid) ans=min(ans,findupper(from,to,num,lson)); if(to>mid) ans=min(ans,findupper(from,to,num,rson)); return ans; } int main(){ int n=read(),m=read(); for(int i=1;i<=n;++i) q[i]=read(); Build(1,n,1); for(register int i=1;i<=m;++i){ int opt=read(); if(opt==1){ int l=read(),r=read(),q=read(); printf("%d\n",findrank(l,r,q,1,n,1)+1); } else if(opt==2){ int l=read(),r=read(),q=read(); int a=0,b=1e8,Ans=0; while(a<=b){ int m=(a+b)>>1; int x=lows(m,1); if(findrank(l,r,x,1,n,1)+1>q) b=m-1; else{ a=m+1; Ans=x; } } printf("%d\n",Ans); } else if(opt==3){ int l=read(),r=read(); Update(l,r,1,n,1); q[l]=r; } else if(opt==4){ int l=read(),r=read(),q=read(); printf("%d\n",findlower(l,r,q,1,n,1)); } else if(opt==5){ int l=read(),r=read(),q=read(); printf("%d\n",findupper(l,r,q,1,n,1)); } } return 0; }