AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1500
【题解】
这是一道很恶心的题,虽然差不多是splay的板子。
我们用mx[x]表示以x为根的子树内最大子串和,lx[x]表示以x为根的子树中以左端点为起点向右延伸的最大子串和,rx[x]表示从右端点向左延伸的最大子串和。
维护rx和lx的过程中要注意单个结点的情况:如果v[x]>=0,rx[x]=lx[x]=v[x],否则rx[x]=lx[x]=0.
坑点:mx[0]=-INF,以及维护过程中不能更新0号结点
没有想明白的地方:翻转标记提前下传的必要性,据Cydiater大神所说,如果不提前下传,在区间修改中会导致翻转标记丢失,但是不懂这是为什么。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define FILE "read"
#define MAXN 500010
#define INF 1000000000
#define up(i,j,n) for(int i=j;i<=n;++i)
#define dn(i,j,n) for(int i=j;i>=n;--i)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
namespace INIT{
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline int read(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();}
return x*f;
}
}using namespace INIT;
int n,m,top,a[MAXN],stack[MAXN];
namespace Splay_Tree{
int root,cnt,f[MAXN],id[MAXN],size[MAXN],sum[MAXN],tag[MAXN],mx[MAXN],v[MAXN],rx[MAXN],lx[MAXN],vis[MAXN],son[MAXN][2];
bool get(int x){return son[f[x]][1]==x;}
void updata(int x){
int l=son[x][0],r=son[x][1];
size[x]=size[l]+size[r]+1; sum[x]=sum[l]+sum[r]+v[x];
mx[x]=max(mx[l],mx[r]); cmax(mx[x],rx[l]+v[x]+lx[r]);
rx[x]=max(rx[r],sum[r]+v[x]+rx[l]); lx[x]=max(lx[l],sum[l]+v[x]+lx[r]);
}
void rotate(int x){
int y=f[x],z=f[y],which=get(x);
son[y][which]=son[x][which^1]; f[son[y][which]]=y;
son[x][which^1]=y; f[y]=x; f[x]=z;
if(z) son[z][son[z][1]==y]=x;
updata(y); updata(x);
}
void splay(int x,int k){
for(int y;(y=f[x]);rotate(x)){
if(x==k) break;
else if(y==k) {rotate(x); break;}
else if(f[y]==k) {rotate(get(x)==get(y)?y:x); rotate(x); break;}
else rotate(get(x)==get(y)?y:x);
}
if(k==root) root=x;
}
void pushdown(int x){
int l=son[x][0],r=son[x][1];
if(tag[x]){
tag[x]=vis[x]=0;
if(l) tag[l]=1,v[l]=v[x],sum[l]=size[l]*v[x],lx[l]=rx[l]=(v[x]>0?sum[l]:0),mx[l]=(v[x]>0?sum[l]:v[l]);
if(r) tag[r]=1,v[r]=v[x],sum[r]=size[r]*v[x],lx[r]=rx[r]=(v[x]>0?sum[r]:0),mx[r]=(v[x]>0?sum[r]:v[r]);
}
if(vis[x]){
vis[l]^=1; vis[r]^=1; vis[x]=0;
swap(lx[l],rx[l]); swap(lx[r],rx[r]);
swap(son[l][0],son[l][1]); swap(son[r][0],son[r][1]);
}
}
void build(int l,int r,int p){
if(l>r) return;
int mid=(l+r)>>1,x=id[mid],y=id[p];
if(l==r){
mx[x]=a[l];sum[x]=a[l];size[x]=1;
tag[x]=vis[x]=0; lx[x]=rx[x]=(a[l]>0?a[l]:0);
}
else build(l,mid-1,mid); build(mid+1,r,mid);
v[x]=a[mid]; f[x]=y; son[y][mid>=p]=x; updata(x);
}
int find(int x){
int now=root;
while(1){
pushdown(now);
int temp=size[son[now][0]];
if(x<=temp) now=son[now][0];
else if(x==temp+1) return now;
else x-=temp+1,now=son[now][1];
}
}
int split(int posi,int tot){
int x=find(posi),y=find(posi+tot+1);
splay(x,root); splay(y,son[x][1]);
return son[y][0];
}
void insert(int posi,int tot){
up(i,1,tot) a[i]=read();
up(i,1,tot) if(top) id[i]=stack[top--];
else id[i]=++cnt;
build(1,tot,0); int z=id[(1+tot)>>1];
int x=find(posi+1),y=find(posi+2);
splay(x,root); splay(y,son[x][1]);
f[z]=y; son[y][0]=z;
updata(y); updata(x);
}
void clear(int x){
if(!x) return;
clear(son[x][0]); clear(son[x][1]);
stack[++top]=x; son[x][0]=son[x][1]=f[x]=vis[x]=tag[x]=0;
}
void del(int posi,int tot){
int x=split(posi,tot),y=f[x];
clear(x);son[y][0]=0;
updata(y); updata(f[y]);
}
void change(int posi,int tot,int c){
int x=split(posi,tot),y=f[x];
tag[x]=1; v[x]=c; sum[x]=size[x]*c;
rx[x]=lx[x]=(c>0?sum[x]:0); mx[x]=(c>0?sum[x]:c);
updata(y); updata(f[y]);
}
void rever(int posi,int tot){
int x=split(posi,tot),y=f[x];
if(tag[x]) return;
vis[x]^=1;
swap(son[x][0],son[x][1]); swap(lx[x],rx[x]);
updata(y); updata(f[y]);
}
void query(int posi,int tot){
int x=split(posi,tot);
printf("%d\n",sum[x]);
}
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
using namespace Splay_Tree;
n=read(); m=read(); mx[0]=a[1]=a[n+2]=-INF;
up(i,1,n) a[i+1]=read();
up(i,1,n+2) id[i]=i;
build(1,n+2,0); root=(n+3)>>1; cnt=n+2;
up(i,1,m){
char ch[15]; scanf("%s",ch+1);
if(ch[1]=='I'){int posi=read(),tot=read(); insert(posi,tot);}
else if(ch[1]=='D'){int posi=read(),tot=read();del(posi,tot);}
else if(ch[1]=='M'){
if(ch[3]=='K'){int posi=read(),tot=read(),c=read();change(posi,tot,c);}
else{printf("%d\n",mx[root]);}
}
else if(ch[1]=='R'){int posi=read(),tot=read();rever(posi,tot);}
else {int posi=read(),tot=read();query(posi,tot);}
}
return 0;
}