正题
是不是觉得标题好奇特,我们想想区间操作怎么用伸展树来实现。
首先我们把左端点的前一个移到根,再把右端点的后一个移到根的右儿子,那么现在根的右儿子的左子树就是我们要求的区间。如下图,我们要求的是[2,4]。那么就把1移到根,5移到右儿子即可。
我们现在已经知道要处理的是哪一棵子树了,我们就可以在这棵子树的根节点打一个标记,表示这棵子树将要被做什么操作。当然,我们要加上一个最前节点和最后节点,来保证整个区间操作时有前一个和后一个。
make_same:
void make_same(int x,int tt,int c){
int ip1=findip(x);//我们先把x的前一个旋到根(其实找的是x-1这个点,但是因为有一个最前节点,所以要往后挪一位)
int ip2=findip(x+tt+1);//找出右节点的下一个
splay(ip1,0);splay(ip2,ip1);//并旋到根
int ip3=s[ip2].son[0];
s[ip3].c=c;//初始化,先把该子树的根节点搞定
s[ip3].same=c;
s[ip3].res=0;//翻转标记可有可无,因为整段区间都是一样的
s[ip3].sum=c*s[ip3].num;//初始化sum
if(c>=0) s[ip3].lmax=s[ip3].rmax=s[ip3].mmax=s[ip3].sum;//后面再讲。
else s[ip3].lmax=s[ip3].rmax=0,s[ip3].mmax=s[ip3].same;
update(ip2);update(ip1);//更新父节点和根
}
reverse:
void reverse(int x,int tt){
int ip1=findip(x);//也是先把区间子树处理出来
int ip2=findip(x+tt+1);
splay(ip1,0);splay(ip2,ip1);
int ip3=s[ip2].son[0];
if(s[ip3].same==-1e9){//如果这段区间一样,那么打不打标记都无所谓
swap(s[ip3].son[0],s[ip3].son[1]);//交换左右儿子,打标记意味着我做了我的子树没做
swap(s[ip3].lmax,s[ip3].rmax);//后面再说
s[ip3].res^=1;//翻转一遍
}
update(ip2);update(ip1);//更新父节点和根
}
这里是看下面:
区间求和相当于上面的操作也变得容易了,那么max_sum怎么做呢emm?
对于每个节点,和他所管理的一个区间(子树),都维护一个lmax和rmax.
分别代表着前缀最大值或后缀最大值,当为负数时都为0(不选)。
那么一个节点所管理区间的区间最大值就是:
1.左儿子的最大值。
2.右儿子的最大值。
3.左儿子的rmax+该节点值+右儿子的lmax.
s[x].mmax=max(s[s[x].son[0]].mmax,max(s[s[x].son[1]].mmax,s[s[x].son[0]].rmax+s[x].c+s[s[x].son[1]].lmax));
同时我们要更新当前区间的最大前缀和最大后缀。
1.选左儿子的最大前缀。
2.选全部左儿子+自己+右边的最大前缀
这样可以包含所有情况。
后缀也是一样的
s[x].lmax=max(s[s[x].son[0]].lmax,s[s[x].son[0]].sum+s[x].c+s[s[x].son[1]].lmax);
s[x].rmax=max(s[s[x].son[1]].rmax,s[s[x].son[1]].sum+s[x].c+s[s[x].son[0]].rmax);
那我们什么时候才去更新儿子呢?
很明显是我们需要经过当前点的时候,我们再找一个点的位置的时候,路上经过的点就是splay的时候可能会改变的点哦~
所以我们需要在findip的时候往下推即可
void pushdown(int x){
if(s[x].same!=-1e9){
int l=s[x].son[0],r=s[x].son[1];
if(l!=0) s[l].c=s[l].same=s[x].same;
if(r!=0) s[r].c=s[r].same=s[x].same;
if(l!=0) s[l].sum=s[l].num*s[l].c;
if(r!=0) s[r].sum=s[r].num*s[r].c;
if(s[x].same>=0){
if(l!=0) s[l].mmax=s[l].lmax=s[l].rmax=s[l].sum;
if(r!=0) s[r].mmax=s[r].lmax=s[r].rmax=s[r].sum;
}
else{
if(l!=0) s[l].lmax=s[l].rmax=0,s[l].mmax=s[l].same;
if(r!=0) s[r].lmax=s[r].rmax=0,s[r].mmax=s[r].same;
}
s[x].same=-1e9;
}
if(s[x].res!=0){
s[s[x].son[0]].res^=1;s[s[x].son[1]].res^=1;
s[x].res=0;
swap(s[s[x].son[0]].lmax,s[s[x].son[0]].rmax);
swap(s[s[x].son[1]].lmax,s[s[x].son[1]].rmax);
swap(s[s[x].son[0]].son[0],s[s[x].son[0]].son[1]);
swap(s[s[x].son[1]].son[0],s[s[x].son[1]].son[1]);
}
}
int findip(int x){
int now=root;
while(1){
pushdown(now);
if(x<=s[s[now].son[0]].num) now=s[now].son[0];
else if(s[s[now].son[0]].num+1<x) x=x-s[s[now].son[0]].num-1,now=s[now].son[1];
else break;
}
return now;
}
最后,一开始建树的时候要二分建树来保证自己不被卡常emmm。
void build(int x,int y,int t){
int mid=(x+y)/2;
s[t].c=a[mid];
s[t].same=-1e9;s[t].res=0;
s[t].son[0]=s[t].son[1]=0;s[t].num=0;s[t].sum=a[mid];s[t].mmax=-1e9;
s[t].lmax=s[t].rmax=0;
int op;
if(x<mid) {
op=f.front();f.pop();
s[t].son[0]=op;
s[op].f=t;
build(x,mid-1,op);
}
if(mid<y){
op=f.front();f.pop();
s[t].son[1]=op;
s[op].f=t;
build(mid+1,y,op);
}
update(t);
}
s[0].mmax=a[0]=a[n+2]=1e9;
当然为了保证我们加进去的点不被选中,要加上一句话。(就这样被卡了2天)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
int n,m;
int a[1000017];
struct tree{
int son[2],lmax,rmax,mmax,f,sum,num,c;
int res,same;
}s[1000017];
int root=0;
queue<int> f;
void update(int x){
s[x].num=s[s[x].son[0]].num+s[s[x].son[1]].num+1;
s[x].sum=s[s[x].son[0]].sum+s[s[x].son[1]].sum+s[x].c;
s[x].lmax=max(s[s[x].son[0]].lmax,s[s[x].son[0]].sum+s[x].c+s[s[x].son[1]].lmax);
s[x].rmax=max(s[s[x].son[1]].rmax,s[s[x].son[1]].sum+s[x].c+s[s[x].son[0]].rmax);
s[x].mmax=max(s[s[x].son[0]].mmax,max(s[s[x].son[1]].mmax,s[s[x].son[0]].rmax+s[x].c+s[s[x].son[1]].lmax));
}
void pushdown(int x){
if(s[x].same!=-1e9){
int l=s[x].son[0],r=s[x].son[1];
if(l!=0) s[l].c=s[l].same=s[x].same;
if(r!=0) s[r].c=s[r].same=s[x].same;
if(l!=0) s[l].sum=s[l].num*s[l].c;
if(r!=0) s[r].sum=s[r].num*s[r].c;
if(s[x].same>=0){
if(l!=0) s[l].mmax=s[l].lmax=s[l].rmax=s[l].sum;
if(r!=0) s[r].mmax=s[r].lmax=s[r].rmax=s[r].sum;
}
else{
if(l!=0) s[l].lmax=s[l].rmax=0,s[l].mmax=s[l].same;
if(r!=0) s[r].lmax=s[r].rmax=0,s[r].mmax=s[r].same;
}
s[x].same=-1e9;
}
if(s[x].res!=0){
s[s[x].son[0]].res^=1;s[s[x].son[1]].res^=1;
s[x].res=0;
swap(s[s[x].son[0]].lmax,s[s[x].son[0]].rmax);
swap(s[s[x].son[1]].lmax,s[s[x].son[1]].rmax);
swap(s[s[x].son[0]].son[0],s[s[x].son[0]].son[1]);
swap(s[s[x].son[1]].son[0],s[s[x].son[1]].son[1]);
}
}
int findip(int x){
int now=root;
while(1){
pushdown(now);
if(x<=s[s[now].son[0]].num) now=s[now].son[0];
else if(s[s[now].son[0]].num+1<x) x=x-s[s[now].son[0]].num-1,now=s[now].son[1];
else break;
}
return now;
}
void build(int x,int y,int t){
int mid=(x+y)/2;
s[t].c=a[mid];
s[t].same=-1e9;s[t].res=0;
s[t].son[0]=s[t].son[1]=0;s[t].num=0;s[t].sum=a[mid];s[t].mmax=-1e9;
s[t].lmax=s[t].rmax=0;
int op;
if(x<mid) {
op=f.front();f.pop();
s[t].son[0]=op;
s[op].f=t;
build(x,mid-1,op);
}
if(mid<y){
op=f.front();f.pop();
s[t].son[1]=op;
s[op].f=t;
build(mid+1,y,op);
}
update(t);
}
void rotate(int x,int w){
int f=s[x].f,ff=s[f].f;
s[f].son[1-w]=s[x].son[w];
if(s[x].son[w]!=0) s[s[x].son[w]].f=f;
if(s[ff].son[0]==f) s[ff].son[0]=x;
else s[ff].son[1]=x;
s[x].f=ff;
s[f].f=x;
s[x].son[w]=f;
update(f);
update(x);
}
void splay(int x,int tar){
while(s[x].f!=tar){
int f=s[x].f,ff=s[f].f;
if(ff==tar){
if(s[f].son[0]==x) rotate(x,1);
else rotate(x,0);
}
else{
if(s[ff].son[0]==f){
if(s[f].son[0]==x) {rotate(f,1);rotate(x,1);}
else {rotate(x,0);rotate(x,1);}
}
else{
if(s[f].son[0]==x) {rotate(x,1);rotate(x,0);}
else {rotate(f,0);rotate(x,0);}
}
}
}
if(tar==0) root=x;
}
void insert(int x,int tot){
int op=f.front();
f.pop();
build(1,tot,op);
int ip1=findip(x+1);
int ip2=findip(x+2);
splay(ip1,0);
splay(ip2,ip1);
s[ip2].son[0]=op;
s[op].f=ip2;
update(ip2);
update(ip1);
}
void recycle(int x){
if(s[x].son[0]) recycle(s[x].son[0]);
if(s[x].son[1]) recycle(s[x].son[1]);
f.push(x);
s[x].son[0]=s[x].son[1]=0;s[x].num=s[x].sum=0;
s[x].c=0;s[x].f=0;s[x].same=-1e9;s[x].mmax=-1e9;
}
void del(int x,int tt){
int ip1=findip(x);
int ip2=findip(x+tt+1);
splay(ip1,0);splay(ip2,ip1);
recycle(s[ip2].son[0]);
s[ip2].son[0]=0;
update(ip2);
update(ip1);
}
void make_same(int x,int tt,int c){
int ip1=findip(x);
int ip2=findip(x+tt+1);
splay(ip1,0);splay(ip2,ip1);
int ip3=s[ip2].son[0];
s[ip3].c=c;
s[ip3].same=c;
s[ip3].res=0;
s[ip3].sum=c*s[ip3].num;
if(c>=0) s[ip3].lmax=s[ip3].rmax=s[ip3].mmax=s[ip3].sum;
else s[ip3].lmax=s[ip3].rmax=0,s[ip3].mmax=s[ip3].same;
update(ip2);update(ip1);
}
void reverse(int x,int tt){
int ip1=findip(x);
int ip2=findip(x+tt+1);
splay(ip1,0);splay(ip2,ip1);
int ip3=s[ip2].son[0];
if(s[ip3].same==-1e9){
swap(s[ip3].son[0],s[ip3].son[1]);
swap(s[ip3].lmax,s[ip3].rmax);
s[ip3].res^=1;
}
update(ip2);update(ip1);
}
int get_tot(int x,int tt){
int ip1=findip(x);
int ip2=findip(x+tt+1);
splay(ip1,0);splay(ip2,ip1);
update(ip2);
update(ip1);
return s[s[ip2].son[0]].sum;
}
int main(){
s[0].mmax=-1e9;
s[0].lmax=s[0].rmax=s[0].sum=s[0].num=0;
scanf("%d %d",&n,&m);
a[1]=a[n+2]=-1e9;
for(int i=1;i<=1000002;i++) f.push(i);
for(int i=2;i<=n+1;i++)
scanf("%d",&a[i]);
int op=f.front();
root=op;
f.pop();
build(1,n+2,op);
char c[20];
int posi,tot,cc;
for(int i=1;i<=m;i++){
scanf("%s",c);
if(!(c[0]=='M' && c[1]=='A' && c[2]=='X')) scanf("%d %d",&posi,&tot);
if(c[0]=='I'){
for(int j=1;j<=tot;j++)
scanf("%d",&a[j]);
insert(posi,tot);
}
else if(c[0]=='D') del(posi,tot);
else if(c[0]=='M' && c[1]=='A' && c[2]=='K'){
scanf("%d",&cc);
make_same(posi,tot,cc);
}
else if(c[0]=='R') reverse(posi,tot);
else if(c[0]=='G') printf("%d\n",get_tot(posi,tot));
else {
//printf("%d %d\n",s[s[root].son[0]].mmax,s[s[root].son[1]].mmax);
printf("%d\n",s[root].mmax);
}
}
}