Description
Input
输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
Output
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
Sample Input
9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM
Sample Output
-1
10
1
10
10
1
10
这题是裸的平衡树。不过我却调了很久,果然还是太渣。
最大和子序列比较难维护,我是先维护LMAX表示从左边起区间的连续最大和,RMAX表示从右边起区间的连续最大和,然后SUM1(最大和子序列)就是等于MAX(SUM1[LC[X]],SUM1[RC[X]],LMAX[RC[X]]+KEY[X]+RMAX[LC[X]])
其他的好像都不难,记得插入的时候不要一个一个插
很明显我们要设定2个标记,翻转的时候交换左右儿子,记住这时候要交换LMAX和RMAX,最后注意下区间覆盖可能为0,因为这个我调了好久......
好了废话不说附上代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int MAXX=500100;
int fa[MAXX],lc[MAXX],rc[MAXX],root,lmax[MAXX],sum[MAXX],rmax[MAXX],sum1[MAXX];
int fan[MAXX],cnt[MAXX],lentag[MAXX],len,qq[MAXX],top=0,sbt=0,size[MAXX],key[MAXX];
int a[MAXX],i,j,k,l,n,m,x,y,z,num;
char s[15];
int get()
{
char c;
while (((c=getchar())<48||c>57)&&c!='-');
if (c=='-')
{
int res=0;
while ((c=getchar())>=48&&c<=57)
res=res*10+c-'0';
return -res;
}
else{
int res=c-'0';
while ((c=getchar())>=48&&c<=57)
res=res*10+c-'0';
return res;
}
}
void pushup(int y)
{
int lson=lc[y],rson=rc[y];
size[y]=size[lson]+size[rson]+1;
sum[y]=sum[lson]+sum[rson]+key[y];
lmax[y]=max(lmax[lson],sum[lson]+key[y]+max(0,lmax[rson]));
rmax[y]=max(rmax[rson],sum[rson]+key[y]+max(0,rmax[lson]));
sum1[y]=max(sum1[lson],sum1[rson]);
sum1[y]=max(max(rmax[lson],0)+key[y]+max(lmax[rson],0),sum1[y]);
}
void turn(int x)
{
int y=fa[x],z=fa[y],b=0;
if (x==lc[y]) b=rc[x];
else b=lc[x];
if (b) fa[b]=y;
fa[x]=z;fa[y]=x;
if (z)
if (lc[z]==y) lc[z]=x;
else rc[z]=x;
if (x==lc[y]) rc[x]=y,lc[y]=b;
else lc[x]=y,rc[y]=b;
pushup(y);
}
void putdown1(int x,int y)
{
sum[x]=size[x]*y;
key[x]=y;
if (y<=0) lmax[x]=rmax[x]=sum1[x]=y;
else lmax[x]=rmax[x]=sum1[x]=y*size[x];
cnt[x]=1;
}
void rev(int x)
{
swap(lmax[x],rmax[x]);
swap(lc[x],rc[x]);
fan[x]^=1;
}
void putdown(int x)
{
int lson=lc[x],rson=rc[x],w=key[x];
if (fan[x])
{
if (lson) rev(lson);
if (rson) rev(rson);
fan[x]=0;
}
if (cnt[x])
{
if (lson) putdown1(lson,w);
if (rson) putdown1(rson,w);
cnt[x]=0;
}
}
void splay(int x,int y)
{
/*len=0;
for(int i=x;i;i=fa[i])
lentag[++len]=i;
while (len) putdown(lentag[len--]); */
while (fa[x]!=y)
{
if (fa[fa[x]]!=y)
if ((lc[fa[x]]==x)==(lc[fa[fa[x]]]==fa[x])) turn(fa[x]);
else turn(x);
turn(x);
}
pushup(x);
if (!y) root=x;
}
int find(int k,int p)
{
while (p!=size[lc[k]]+1)
{
putdown(k);
if (p>size[lc[k]]+1)
p=p-size[lc[k]]-1,k=rc[k];
else k=lc[k];
}
putdown(k);
return k;
}
void start(int p,int q,int &k,int yy)
{
if (p>q) return;
if (!k)
{
if (top) k=qq[top--];
else k=++sbt;
}
int mid=(p+q)>>1;
key[k]=a[mid];
fa[k]=yy;
start(p,mid-1,lc[k],k);
start(mid+1,q,rc[k],k);
pushup(k);
}
void shouji(int k)
{
if (!k) return;
qq[++top]=k;
shouji(lc[k]);
shouji(rc[k]);
key[k]=fa[k]=lc[k]=rc[k]=sum[k]=size[k]=cnt[k]=fan[k]=0;
lmax[k]=rmax[k]=sum1[k]=-707406378;
}
int main()
{
n=get();m=get();
memset(lmax,-127/3,sizeof(lmax));
memset(rmax,-127/3,sizeof(rmax));
memset(sum1,-127/3,sizeof(sum1));
for(i=1;i<=n;i++)
a[i]=get();
start(0,n+1,root,0);
root=1;
for(i=1;i<=m;i++)
{
scanf("%s",s);
if (s[0]=='I') //加数
{
x=get();y=get();
for(j=1;j<=y;j++)
a[j]=get();
int k=find(root,x+1);
int kk=find(root,x+2);
splay(k,0);splay(kk,k);
start(1,y,lc[kk],kk);
pushup(kk);
pushup(k);
}
if (s[0]=='D') //删数
{
x=get();y=get();
int k=find(root,x);
int kk=find(root,x+y+1);
splay(k,0);splay(kk,k);
shouji(lc[kk]);
lc[kk]=0;
pushup(kk);
pushup(k);
}
if (s[0]=='M'&&s[2]=='K') //区间覆盖
{
x=get();y=get();z=get();
int k=find(root,x);
int kk=find(root,x+1+y);
splay(k,0);splay(kk,k);
putdown1(lc[kk],z);
pushup(kk);
pushup(k);
}
if (s[0]=='R') //区间翻转
{
x=get();y=get();
int k=find(root,x);
int kk=find(root,x+1+y);
splay(k,0);splay(kk,k);
if (lc[kk]&&!fan[lc[kk]]) rev(lc[kk]);
pushup(kk);
pushup(k);
}
if (s[0]=='G') //和
{
x=get();y=get();
int k=find(root,x);
int kk=find(root,x+y+1);
splay(k,0);splay(kk,k);
printf("%d\n",sum[lc[kk]]);
}
if (s[0]=='M'&&s[2]=='X') //最大和
{
int k=find(root,1);
int kk=find(root,size[root]);
splay(k,0);splay(kk,k);
printf("%d\n",sum1[lc[kk]]);
}
}
}