平衡树区间操作板子
前几天知道平衡树也能像线段树一样实现操作。
并且还能轻易实现一些线段树很难做到的东西。
如区间翻转。
以下题目本人均用\(fhq-treap\)完成
先完成文艺平衡树、序列终结者和[CQOI2014]排序机械臂
接下来的一道经典例题大概就是上面的三道的总和
[NOI2005] 维护数列
题目大意
实现一个数据结构,支持一下操作:
- 在任意位置插入一堆数
- 在任意位置删除一堆数
- 在任意位置修改一堆数
- 翻转任意区间
- 查询任意区间和
- 查询整个序列的最大子段和
做完先前三题你就能知道大致思路了,下面讲述一些注意事项。
- 对于插入,很显然不能一个一个插,你可以先把要插入的\(tot\)个数形成一棵平衡树,然后与原序列的平衡树合并。
但这样会\(T\)掉\(20pts\),其实你就可以像线段树那样“分治建树”,可以很巧妙的将插入复杂度由\(O(totlog_2tot)\)降为\((log^2tot)\)。 - 此题卡空间,在删除时应该“回收利用”节点编号。
- 一些零碎的细节:最大子段和不能为空,记得\(pushdown\)和\(update\),不要操作空节点等。
code:
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,T,cnt,rt;
int ls[N],rs[N],val[N],siz[N],pfer[N];
int sum[N],lmx[N],rmx[N],a[N];
int rev[N],tag[N],dat[N];
int sk[N],top;
bool ct[N];
int read(){
int A=0,F=1;
char C=getchar();
while(C<'0'||C>'9'){if(C=='-')F=-1;C=getchar();}
while(C>='0'&&C<='9'){A=(A<<1)+(A<<3)+C-'0';C=getchar();}
return A*F;
}
int New(int k){
int p=top?sk[top--]:++cnt;
ls[p]=rs[p]=rev[p]=tag[p]=ct[p]=0;
sum[p]=k;val[p]=k;
lmx[p]=max(k,0);
rmx[p]=max(k,0);
dat[p]=k;
siz[p]=1;pfer[p]=rand()*rand();
return p;
}
void update(int p){
if(!p)return;
siz[p]=siz[ls[p]]+siz[rs[p]]+1;
sum[p]=sum[ls[p]]+sum[rs[p]]+val[p];
lmx[p]=max(max(lmx[ls[p]],sum[ls[p]]+val[p]+lmx[rs[p]]),0);
rmx[p]=max(max(rmx[rs[p]],sum[rs[p]]+val[p]+rmx[ls[p]]),0);
dat[p]=max(val[p],val[p]+rmx[ls[p]]+lmx[rs[p]]);
if(ls[p])dat[p]=max(dat[p],dat[ls[p]]);
if(rs[p])dat[p]=max(dat[p],dat[rs[p]]);
}
void Re(int p){
if(!p)return;
swap(ls[p],rs[p]);
swap(lmx[p],rmx[p]);
rev[p]^=1;
}
void Co(int p,int v){
val[p]=tag[p]=v;
sum[p]=siz[p]*v;
lmx[p]=rmx[p]=max(0,sum[p]);
dat[p]=max(v,sum[p]);
ct[p]=1;
}
void pushdown(int p){
if(!p)return;
if(rev[p]){
if(ls[p])Re(ls[p]);
if(rs[p])Re(rs[p]);
rev[p]=0;
}
if(ct[p]){
if(ls[p])Co(ls[p],tag[p]);
if(rs[p])Co(rs[p],tag[p]);
tag[p]=ct[p]=0;
}
}
void split(int p,int sz,int &x,int &y){
if(!p){x=y=0;return;}
pushdown(p);
if(siz[ls[p]]+1<=sz){x=p;split(rs[p],sz-siz[ls[p]]-1,rs[p],y);}
else{y=p;split(ls[p],sz,x,ls[p]);}
update(p);
}
int merge(int x,int y){
if(!x||!y)return x+y;
if(pfer[x]>pfer[y]){
pushdown(x);
rs[x]=merge(rs[x],y);
update(x);
return x;
}
else{
pushdown(y);
ls[y]=merge(x,ls[y]);
update(y);
return y;
}
}
void recycle(int p){
if(!p)return;
sk[++top]=p;
recycle(ls[p]);
recycle(rs[p]);
}
void del(int l,int r){
int x,y,z;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
recycle(y);
rt=merge(x,z);
}
void modify(int l,int r,int k){
int x,y,z;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
Co(y,k);
rt=merge(merge(x,y),z);
}
void reverse(int l,int r){
int x,y,z;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
Re(y);
rt=merge(merge(x,y),z);
}
int qsum(int l,int r){
int x,y,z,ans;
split(rt,l-1,x,y);
split(y,r-l+1,y,z);
ans=sum[y];
rt=merge(merge(x,y),z);
return ans;
}
int Buld(int l,int r){
if(l==r)return New(a[l]);
int mid=l+r>>1,now;
now=merge(Buld(l,mid),Buld(mid+1,r));
return now;
}
int main(){
srand(time(0));
// freopen("P2042_8.in","r",stdin);
// freopen("ans.out","w",stdout);
// double st=clock();
n=read();T=read();
for(int i=1;i<=n;i++){
int x;
x=read();
rt=merge(rt,New(x));
}
while(T--){
char op[30];
scanf("%s",op);
int w,c,x;
if(op[0]=='I'){
w=read();c=read();
int TpT=0;
for(int i=1;i<=c;i++)a[i]=read();
TpT=Buld(1,c);
int x,y,z;
split(rt,w,x,y);
rt=merge(merge(x,TpT),y);
}
else if(op[0]=='D'){
w=read();c=read();
del(w,w+c-1);
}
else if(op[2]=='K'){
w=read();c=read();x=read();
modify(w,w+c-1,x);
}
else if(op[0]=='R'){
w=read();c=read();
reverse(w,w+c-1);
}
else if(op[0]=='G'){
w=read();c=read();
printf("%d\n",qsum(w,w+c-1));
}
else if(op[0]=='M')printf("%d\n",dat[rt]);
}
//cout<<clock()-st;
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步