1 条题解
-
0
自动搬运
来自洛谷,原作者为

破忆
一个loser而已搬运于
2025-08-24 21:40:42,当前版本为作者最后更新于2020-10-26 13:26:38,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
【题意】
维护一个序列
支持插入、删除、翻转、覆盖、求和、求最大子段和操作
【分析】
经典数据结构题
没什么思维难度,直接上吧
明确需要维护的信息
翻转和覆盖,需要打两个懒标记
求和需要区间和
求最大子段和需要区间最大前缀、最大后缀与最大子段和
还有随机键值、区间大小、左右子树
struct fhq_treap{ int rand,siz,rev,cov,son[2],val; LL max,s,l,r; }t[maxt];上传信息、下发标记
线段树和平衡树的基本操作,比较套路
IN void pushup(RE int k){ t[k].siz=t[ls].siz+t[rs].siz+1; t[k].s=t[ls].s+t[rs].s+t[k].val; t[k].l=max(t[ls].l,max(0ll,t[ls].s+t[k].val+t[rs].l)); t[k].r=max(t[rs].r,max(0ll,t[rs].s+t[k].val+t[ls].r)); t[k].max=max((LL)t[k].val,t[ls].r+t[k].val+t[rs].l); if(ls) t[k].max=max(t[k].max,t[ls].max); if(rs) t[k].max=max(t[k].max,t[rs].max); }IN void pushdown(RE int k){ if(t[k].cov!=INF){ LL c=t[k].cov; if(ls) cov(ls,c); if(rs) cov(rs,c); t[k].cov=INF; } if(t[k].rev){ if(ls) rev(ls); if(rs) rev(rs); t[k].rev=0; } }fhq-treap合并、分裂板子
int merge(RE int x,RE int y){ if(!x||!y) return x+y; if(t[x].rand<t[y].rand){ pushdown(x); t[x].son[1]=merge(t[x].son[1],y); pushup(x); return x; } else{ pushdown(y); t[y].son[0]=merge(x,t[y].son[0]); pushup(y); return y; } }void splits(RE int now,RE int k,RE int &x,RE int &y){ if(!now){ x=y=0; return; } pushdown(now); if(k<=t[t[now].son[0]].siz){ y=now; splits(t[y].son[0],k,x,t[y].son[0]); pushup(y); } else{ x=now; splits(t[x].son[1],k-t[t[x].son[0]].siz-1,t[x].son[1],y); pushup(x); } pushup(now); }插入与删除
插入仿照线段树建树方式,而不是逐个插入,可以更平衡
删点时把没用的点存入栈,以便下次使用
IN int build(RE int k){ RE int now=top?stk[top--]:++cnt; t[now].rand=rand(); t[now].cov=INF; t[now].rev=0; t[now].son[0]=t[now].son[1]=0; t[now].max=t[now].s=t[now].val=k; t[now].l=t[now].r=max(k,0); t[now].siz=1; return now; } int build(RE int l,RE int r){ if(l==r) return build(read()); int x=build(l,mid),y=build(mid+1,r); return merge(x,y); }void del(RE int k){ if(ls) del(ls); if(rs) del(rs); stk[++top]=k; } IN void del(RE int l,RE int r){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); del(y); rt=merge(x,z); }覆盖与翻转
分离出待操作区间,然后打上标记,顺便更新信息
IN void cov(RE int k,RE int c){ t[k].cov=t[k].val=c; t[k].s=(LL)t[k].siz*c; t[k].l=t[k].r=max(0ll,t[k].s); t[k].max=max((LL)c,t[k].s); } IN void cover(RE int l,RE int r,RE int c){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); cov(y,c); rt=merge(merge(x,y),z); }IN void rev(RE int k){ if(!k) return; swap(t[k].l,t[k].r); swap(t[k].son[0],t[k].son[1]); t[k].rev^=1; } IN void reverse(RE int l,RE int r){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); rev(y); rt=merge(merge(x,y),z); }询问
分离出区间输出即可
IN LL query(RE int l,RE int r){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); RE LL ret=t[y].s; rt=merge(merge(x,y),z); return ret; }IN LL maxs(RE int l,RE int r){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); LL ret=t[y].max; rt=merge(merge(x,y),z); return ret; }算法
fhq-treap
提醒
细节多,代码长
以下几个地方值得注意
翻转时要交换最大前缀和最大后缀
下传标记时,先覆盖再翻转
建树时,先提取出子树再合并,不能写成这样,否则会有意想不到的错误
merge(build(l,mid),build(mid+1,r))若没有覆盖标记时,懒标记应该设置成一个不可能出现的值,设成-1,0之类的就完了
记得开longlong
代码
#include<bits/stdc++.h> #define LL long long #define ls t[k].son[0] #define rs t[k].son[1] #define mid (l+r>>1) #define IN inline #define RE register using namespace std; const int maxt=5e5+5,INF=1<<30; int n,m; int top,stk[maxt]; int cnt,rt; char z[15]; struct fhq_treap{ int rand,siz,rev,cov,son[2],val; LL max,s,l,r; }t[maxt]; IN int read(){ RE int ret=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } IN void rev(RE int k){ if(!k) return; swap(t[k].l,t[k].r); swap(t[k].son[0],t[k].son[1]); t[k].rev^=1; } IN void cov(RE int k,RE int c){ t[k].cov=t[k].val=c; t[k].s=(LL)t[k].siz*c; t[k].l=t[k].r=max(0ll,t[k].s); t[k].max=max((LL)c,t[k].s); } IN void pushup(RE int k){ t[k].siz=t[ls].siz+t[rs].siz+1; t[k].s=t[ls].s+t[rs].s+t[k].val; t[k].l=max(t[ls].l,max(0ll,t[ls].s+t[k].val+t[rs].l)); t[k].r=max(t[rs].r,max(0ll,t[rs].s+t[k].val+t[ls].r)); t[k].max=max((LL)t[k].val,t[ls].r+t[k].val+t[rs].l); if(ls) t[k].max=max(t[k].max,t[ls].max); if(rs) t[k].max=max(t[k].max,t[rs].max); } IN void pushdown(RE int k){ if(t[k].cov!=INF){ LL c=t[k].cov; if(ls) cov(ls,c); if(rs) cov(rs,c); t[k].cov=INF; } if(t[k].rev){ if(ls) rev(ls); if(rs) rev(rs); t[k].rev=0; } } void splits(RE int now,RE int k,RE int &x,RE int &y){ if(!now){ x=y=0; return; } pushdown(now); if(k<=t[t[now].son[0]].siz){ y=now; splits(t[y].son[0],k,x,t[y].son[0]); pushup(y); } else{ x=now; splits(t[x].son[1],k-t[t[x].son[0]].siz-1,t[x].son[1],y); pushup(x); } pushup(now); } int merge(RE int x,RE int y){ if(!x||!y) return x+y; if(t[x].rand<t[y].rand){ pushdown(x); t[x].son[1]=merge(t[x].son[1],y); pushup(x); return x; } else{ pushdown(y); t[y].son[0]=merge(x,t[y].son[0]); pushup(y); return y; } } IN int build(RE int k){ RE int now=top?stk[top--]:++cnt; t[now].rand=rand(); t[now].cov=INF; t[now].rev=0; t[now].son[0]=t[now].son[1]=0; t[now].max=t[now].s=t[now].val=k; t[now].l=t[now].r=max(k,0); t[now].siz=1; return now; } void del(RE int k){ if(ls) del(ls); if(rs) del(rs); stk[++top]=k; } int build(RE int l,RE int r){ if(l==r) return build(read()); int x=build(l,mid),y=build(mid+1,r); return merge(x,y); } IN void del(RE int l,RE int r){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); del(y); rt=merge(x,z); } IN void cover(RE int l,RE int r,RE int c){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); cov(y,c); rt=merge(merge(x,y),z); } IN void reverse(RE int l,RE int r){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); rev(y); rt=merge(merge(x,y),z); } IN LL query(RE int l,RE int r){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); RE LL ret=t[y].s; rt=merge(merge(x,y),z); return ret; } IN LL maxs(RE int l,RE int r){ RE int x,y,z; splits(rt,r,x,z); splits(x,l-1,x,y); LL ret=t[y].max; rt=merge(merge(x,y),z); return ret; } int main(){ freopen("P2710.in","r",stdin); freopen("P2710.out","w",stdout); n=read(),m=read(); rt=build(1,n); for(RE int i=1;i<=m;i++){ scanf("%s",z); if(z[0]=='I'){ RE int pos=read(),tot=read(); RE int x,y; splits(rt,pos,x,y); rt=merge(merge(x,build(pos,pos+tot-1)),y); }else if(z[0]=='D'){ RE int pos=read(),tot=read(); del(pos,pos+tot-1); }else if(z[0]=='R'){ RE int pos=read(),tot=read(); reverse(pos,pos+tot-1); }else if(z[2]=='K'){ RE int pos=read(),tot=read(),c=read(); cover(pos,pos+tot-1,c); }else if(z[1]=='A'){ RE int pos=read(),tot=read(); printf("%lld\n",maxs(pos,pos+tot-1)); }else if(strlen(z)>4){ RE int pos=read(),tot=read(); printf("%lld\n",query(pos,pos+tot-1)); } else{ RE int pos=read(); printf("%lld\n",query(pos,pos)); } } return 0; }最后
保持一个平和的心态
- 1
信息
- ID
- 1747
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者