题意:给你一个数列,每次可能插入一些数,删除一些数,翻转一个区间,询问一个区间的和,还有询问最大的和区间,将一个区间置为相同的一个值。。。
分析:赋值,删除,插入,还有区间和,都比较简单,而翻转和求最大区间和,这个比较麻烦,用到线段树的延迟标记,翻转的话,和赋值差不多,加一个翻转标记,每次下传时,对调两个子节点就行,而最大区间和值,这个需要维护三个值域,一个区间最左开始的最大和,一个区间最右开始的最大和,还有这个区间的最大和。。。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define M 500010
#define inf 1<<30
#define keytree (c[c[root][1]][0])
//变量定义,根据题意而定。
int p[M],c[M][2],s[M],v[M],rev[M],same[M];
int Lmax[M],Rmax[M],Max[M],d[M],sum[M];
int root,n,m,len,top1,top2,sta[M],que[M];
//根据左右子树来更新父亲。。
inline void push_up(int x)
{
if(!x) return;
int l=c[x][0],r=c[x][1];
s[x]=1+s[l]+s[r];
sum[x]=v[x]+sum[l]+sum[r];
Lmax[x]=max(Lmax[l],sum[l]+v[x]+max(0,Lmax[r]));
Rmax[x]=max(Rmax[r],sum[r]+v[x]+max(0,Rmax[l]));
Max[x]=max(Lmax[r],0)+v[x]+max(Rmax[c[x][0]],0);
Max[x]=max(Max[x],max(Max[l],Max[r]));
}
//反转更新。。
inline void Date_rev(int x)
{
if(!x) return;
swap(c[x][0],c[x][1]);
swap(Lmax[x],Rmax[x]);
rev[x]^=1;
}
//区间更新成同一个值。。
inline void Date_same(int x,int val)
{
if(!x) return;
v[x]=val,sum[x]=s[x]*val;
Lmax[x]=Rmax[x]=Max[x]=max(v[x],sum[x]);
same[x]=1;
}
//lazy操作,更新当前需要更新的。。
inline void push_down(int x)
{
if(!x) return;
if(rev[x])
{
Date_rev(c[x][0]);
Date_rev(c[x][1]);
}
if(same[x])
{
Date_same(c[x][0],v[x]);
Date_same(c[x][1],v[x]);
}
rev[x]=same[x]=0;
}
//开辟节点,通常为固定模式,改变的仅仅为部分变量。。
inline void newnode(int &x,int val)
{
if(top2) x=sta[top2--];
else x=++top1;
s[x]=1;
p[x]=c[x][0]=c[x][1]=same[x]=rev[x]=0;
v[x]=Lmax[x]=Rmax[x]=Max[x]=sum[x]=val;
}
//建树插入节点。。
inline void build(int &x,int l,int r,int pre)
{
if(l>r) return;
int mid=(l+r)>>1;
newnode(x,d[mid]);
build(c[x][0],l,mid-1,x);
build(c[x][1],mid+1,r,x);
p[x]=pre,push_up(x);
}
//初始话,基本上固定,改变的仅仅是部分变量。。
inline void Splay_init()
{
root=top1=top2=same[0]=rev[0]=sum[0]=0;
p[0]=c[0][0]=c[0][1]=s[0]=v[0]=0;
Lmax[0]=Rmax[0]=Max[0]=-1001;
newnode(root,-inf);
newnode(c[root][1],-inf);
p[top1]=root,s[root]=2;
build(keytree,1,n,c[root][1]);
push_up(c[root][1]);
push_up(root);
}
//旋转函数,内容基本固定。。
inline void Rotate(int x,int f)
{
int y=p[x];
push_down(y),push_down(x);
c[y][!f]=c[x][f];
p[c[x][f]]=y;
p[x]=p[y];
if(p[x]) c[p[y]][c[p[y]][1]==y]=x;
p[y]=x,c[x][f]=y;
push_up(y);
}
//伸展函数,内容基本固定。。
inline void Splay(int x,int goal)
{
while(p[x]!=goal)
{
if(p[p[x]]==goal) Rotate(x,c[p[x]][0]==x);
else
{
int y=p[x],f=c[p[y]][0]==y;
if(c[y][f]==x) Rotate(x,!f);
else Rotate(y,f);
Rotate(x,f);
}
}
push_up(x);
if(!goal) root=x;
}
//查找第k个元素,内容基本固定。。
inline void RotateTo(int k,int goal)
{
int x=root;
push_down(x);
while(s[c[x][0]]!=k)
{
if(s[c[x][0]]>k) x=c[x][0];
else k-=s[c[x][0]]+1,x=c[x][1];
push_down(x);
}
Splay(x,goal);
}
//删除以x节点为祖先的子树,回收内存。
//通常为题目数据较大是应用。。。
inline void erase(int x)
{
int head=1,rear=1;
que[head]= x;
while(head<=rear)
{
sta[++top2]=que[head];
if(c[que[head]][0]) que[++rear]=c[que[head]][0];
if(c[que[head]][1]) que[++rear]=c[que[head]][1];
head++;
}
}
//插入操作,通常也为固定内容。。
inline void Insert(int id)
{
RotateTo(id,0);
RotateTo(id+1,root);
build(keytree,1,len,c[root][1]);
push_up(c[root][1]),push_up(root);
}
//删除函数,通常为固定内容。。
inline void Delete(int id,int num)
{
RotateTo(id-1,0);
RotateTo(id+num,root);
erase(keytree); //此处如果题目数据不大可以省略。。
c[c[root][1]][0]=0;
push_up(c[root][1]),push_up(root);
}
//区间操作函数。。
inline void Same(int id,int num,int val)
{
RotateTo(id-1,0);
RotateTo(id+num,root);
Date_same(keytree,val);
}
//滚动
inline void revolve(int l,int r,int num)
{
num%=(r-l+1);
num=(num+(r-l+1))%(r-l+1);
if(!num) return;
RotateTo(r-num,0);
RotateTo(r+1,root);
int x=keyTree;
keyTree=0;
push_up(ch[root][1]);
push_up(root);
RotateTo(l-1,0);
RotateTo(l,root);
keyTree=x;
pre[keyTree]=ch[root][1];
push_up(ch[root][1]);
push_up(root);
}
//反转函数。。
inline void Reverse(int id,int num)
{
RotateTo(id-1,0);
RotateTo(id+num,root);
Date_rev(keytree);
}
inline void Getsum(int id,int num)
{
RotateTo(id-1,0);
RotateTo(id+num,root);
printf("%d\n",sum[keytree]);
}
inline void Max_sum()
{
RotateTo(0,0);
RotateTo(s[root]-1,root);
printf("%d\n",Max[keytree]);
}
int getint()
{
char ch;
int flag = 0, tmp = 0;
for (ch = getchar(); ch < 48 || ch > 57; ch = getchar())
if (ch == int('-')) break;
if (ch == int('-')) flag = 1;
else tmp = int(ch) - 48;
for (ch = getchar(); 48 <= ch && ch <= 57; ch = getchar())
tmp = tmp * 10 + int(ch) - 48;
return (flag) ? -tmp : tmp;
}
int main()
{
char str[20];
int i,aa,bb,cc;
n=getint(),m=getint();
for(i=1;i<=n;i++) d[i]=getint();
Splay_init();
while(m--)
{
scanf("%s",str);
if(str[0]=='I')
{
aa=getint(),len=getint();
for(i=1;i<=len;i++) d[i]=getint();
Insert(aa);
}
else if(str[0]=='D') aa=getint(),bb=getint(),Delete(aa,bb);
else if(str[0]=='R') aa=getint(),bb=getint(),Reverse(aa,bb);
else if(str[0]=='M'&&str[2]=='K')
aa=getint(),bb=getint(),cc=getint(),Same(aa,bb,cc);
else if(str[0]=='G') aa=getint(),bb=getint(),Getsum(aa,bb);
else Max_sum();
}
return 0;
}