题目:BZOJ1500、洛谷P2042、Vijos P1835、codevs1758。
题目大意:
给你一个数列,实现以下操作。
解题思路:
非旋Treap维护数列即可。
前面5个都是基本的平衡树序列操作(第5个维护一个区间和即可)。
第6个要求最大子段和,则我们需要维护以当前节点为子树的子段和,当前子树的最大前缀和和最大后缀和,才能转移出正确的最大子段和。(具体如何维护详见代码)
对于旋转操作,需要把前缀和后缀交换一下。
还有要注意:
1. 内存不能开太大,会MLE,要回收被删除的节点。
2. 插入时不要一个一个merge,先按照笛卡尔树的建树方式建树(O(n)),然后直接merge根即可。
C++ Code:
#include<bits/stdc++.h>
inline int max(int a,int b){return a>b?a:b;}
inline void swap(int& a,int& b){int c=a;a=b,b=c;}
inline int readint(){
int c=getchar(),d=0,b=0;
for(;!isdigit(c);c=getchar())b=c=='-';
for(;isdigit(c);c=getchar())d=(d<<3)+(d<<1)+(c^'0');
return b?-d:d;
}
struct node{
int ls,rs,s,lm,rm,sm,smx,rot,r,tag,sz;
inline void Cng(int val){
s=val;
sm=sz*val;
lm=rm=max(sm,0);
smx=max(sm,s);
tag=1;
}
inline void rev(){
swap(ls,rs);
swap(lm,rm);
rot^=1;
}
}a[500005];
struct Memory_pool{
int p[500005],top;
Memory_pool(){
for(int i=1;i<=500004;++i)p[i]=i;
top=500004;
}
inline int New(){return p[top--];}
inline void Del(int x){p[++top]=x;}
}P;
int n,m,rt,sta[500005],top=0;
inline void pushdown(int x){
if(a[x].rot){
a[x].rot=0;
if(a[x].ls)a[a[x].ls].rev();
if(a[x].rs)a[a[x].rs].rev();
}
if(a[x].tag){
a[x].tag=0;
if(a[x].ls)a[a[x].ls].Cng(a[x].s);
if(a[x].rs)a[a[x].rs].Cng(a[x].s);
}
}
inline void update(int x){
int ls=a[x].ls,rs=a[x].rs,s=a[x].s;
if(ls&&rs){
a[x].sz=a[ls].sz+a[rs].sz+1;
a[x].sm=a[ls].sm+a[rs].sm+s;
a[x].smx=max(a[ls].smx,a[rs].smx);
a[x].smx=max(a[x].smx,a[ls].rm+s+a[rs].lm);
a[x].lm=max(a[ls].lm,a[ls].sm+s+a[rs].lm);
a[x].rm=max(a[rs].rm,a[rs].sm+s+a[ls].rm);
}else
if(ls){
a[x].sz=a[ls].sz+1;
a[x].sm=a[ls].sm+s;
a[x].smx=max(a[ls].smx,a[ls].rm+s);
a[x].lm=max(a[ls].lm,a[ls].sm+s);
a[x].rm=max(a[ls].rm+s,0);
}else
if(rs){
a[x].sz=a[rs].sz+1;
a[x].sm=a[rs].sm+s;
a[x].smx=max(a[rs].smx,a[rs].lm+s);
a[x].rm=max(a[rs].rm,a[rs].sm+s);
a[x].lm=max(a[rs].lm+s,0);
}else{
a[x].sz=1;
a[x].sm=a[x].smx=s;
a[x].lm=a[x].rm=max(s,0);
}
}
int build(int n){
int x,pre;
for(int i=1;i<=n;++i){
int f=readint();
int ff=max(f,0);
a[x=P.New()]=(node){0,0,f,ff,ff,f,f,0,rand(),0,1};
for(pre=0;top&&a[sta[top]].r>a[x].r;--top)update(pre=sta[top]);
if(top)a[sta[top]].rs=x;
a[sta[++top]=x].ls=pre;
}
while(top)update(sta[top--]);
return sta[1];
}
void split(int u,int k,int& x,int& y){
if(!k){
x=0,y=u;
return;
}
if(k==a[u].sz){
x=u,y=0;
return;
}
pushdown(u);
if(a[a[u].ls].sz>=k)split(a[u].ls,k,x,a[u].ls),y=u;else
split(a[u].rs,k-a[a[u].ls].sz-1,a[u].rs,y),x=u;
update(u);
}
int merge(int x,int y){
if(x)pushdown(x);
if(y)pushdown(y);
if(!x||!y)return x|y;
if(a[x].r<a[y].r){
a[x].rs=merge(a[x].rs,y);
update(x);
return x;
}
a[y].ls=merge(x,a[y].ls);
update(y);
return y;
}
void dispose(int now){
if(!now)return;
dispose(a[now].ls);
dispose(a[now].rs);
P.Del(now);
}
int main(){
n=readint(),m=readint();
a[0]=(node){0,0,0,0,0,0,0,0,0,0,0};
srand(20170607);
rt=build(n);
while(m--){
static char s[100];
int tot;
scanf("%s",s);
if(s[0]=='I'){
tot=readint();int rtn=build(readint()),x,y;
split(rt,tot,x,y);
rt=merge(merge(x,rtn),y);
}else
if(s[0]=='D'){
tot=readint(),n=readint();
int x,y,z;
split(rt,tot-1,x,y);
split(y,n,y,z);
dispose(y);
rt=merge(x,z);
}else
if(s[0]=='M'&&s[2]=='K'){
tot=readint(),n=readint();
int x,y,z;
split(rt,tot-1,x,y);
split(y,n,y,z);
a[y].Cng(readint());
rt=merge(merge(x,y),z);
}else
if(s[0]=='R'){
tot=readint(),n=readint();
int x,y,z;
split(rt,tot-1,x,y);
split(y,n,y,z);
a[y].rev();
rt=merge(merge(x,y),z);
}else
if(s[0]=='G'){
tot=readint(),n=readint();
int x,y,z;
split(rt,tot-1,x,y);
split(y,n,y,z);
printf("%d\n",a[y].sm);
rt=merge(merge(x,y),z);
}else printf("%d\n",a[rt].smx);
}
return 0;
}