题解 P2710 【数列】
【题意】
维护一个序列
支持插入、删除、翻转、覆盖、求和、求最大子段和操作
【分析】
经典数据结构题
没什么思维难度,直接上
明确需要维护的信息
翻转和覆盖,需要打两个懒标记
求和需要区间和
求最大子段和需要区间最大前缀、最大后缀与最大子段和
还有随机键值、区间大小、左右子树
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;
}
最后