Description
请写一个程序,要求维护一个数列,支持以下6种操作:(请注意,格式栏中的下划线‘ _ ’表示实际输入文件中的空格)
1. 插入 INSERT_posi_tot_c1_c2_…_ctot 在当前数列的第posi个数字后插入tot个数字:c1, c2, …, ctot;若在数列首插入,则posi为0
2. 删除 DELETE_posi_tot 从当前数列的第posi个数字开始连续删除tot个数字
3. 修改 MAKE-SAME_posi_tot_c 将当前数列的第posi个数字开始的连续tot个数字统一修改为c
4. 翻转 REVERSE_posi_tot 取出从当前数列的第posi个数字开始的tot个数字,翻转后放入原来的位置
5. 求和 GET-SUM_posi_tot 计算从当前数列开始的第posi个数字开始的tot个数字的和并输出
6. 求和最大的子列 MAX-SUM 求出当前数列中和最大的一段子列,并输出最大和
Input
输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
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
Sample Output
-1
10
1
10
Hint
你可以认为在任何时刻,数列中至少有1个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
50%的数据中,任何时刻数列中最多含有30 000个数;
100%的数据中,任何时刻数列中最多含有500 000个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
Solution
维护一个splay,就是维护的东西有点多
因为他的insert总长度可能很长,但他同时不会太长,所以把delete的点放到一个栈里,以后加入的时候使用
需要维护以下东西(数组与我程序中的数组相同)
size[x]表示x子树的大小
da[x]表示x这个位置的真实值
sum[x]表示x子树的和(为了维护操作5)
以下为了维护操作6
l[x]表示x子树所代表的区间左边开始的最大子序列
r[x]表示x子树所代表的区间右边开始的最大子序列
d[x]表示x子树所代表的区间整体的最大子序列
如何转移自己想
注意细节
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 1001000
using namespace std;
int t[N][2],fa[N],s[N],tot,root,s1[N],rev[N],lz[N],l[N],r[N],d[N],sum[N],size[N],da[N],n,m;
int lr(int x){return x==t[fa[x]][1];}
void down(int x,int v)
{
if(!x) return;
da[x]=lz[x]=v;
sum[x]=v*size[x];
if(v>0) l[x]=r[x]=d[x]=size[x]*v;
else l[x]=r[x]=0,d[x]=v;
}
void dow1(int z)
{
if(!z) return;
swap(t[z][0],t[z][1]);
swap(l[z],r[z]);
rev[z]^=1;
}
void dow2(int z)
{
if(!z) return;
if(lz[z]!=N)
{
down(t[z][0],lz[z]);
down(t[z][1],lz[z]);
lz[z]=N;
}
}
void turn(int z)
{
if(!z) return;
if(rev[z]) dow1(t[z][0]),dow1(t[z][1]),rev[z]=0;
}
void xc(int x,int y)
{
s1[0]=0;
for(;x!=y;x=fa[x]) s1[++s1[0]]=x;
for(;s1[0];s1[0]--)
{
int z=s1[s1[0]];
dow2(z);
turn(z);
}
}
void update(int x)
{
if(x==1||x==n+2||x==n+3) d[x]=-214748347;
else d[x]=r[t[x][0]]+da[x]+l[t[x][1]];
sum[x]=sum[t[x][0]]+sum[t[x][1]]+da[x];
size[x]=size[t[x][0]]+size[t[x][1]]+1;
if(t[x][0]) d[x]=max(d[x],d[t[x][0]]);
if(t[x][1]) d[x]=max(d[x],d[t[x][1]]);
l[x]=r[x]=0;
l[x]=max(l[t[x][0]],sum[t[x][0]]+da[x]+l[t[x][1]]);
r[x]=max(r[t[x][1]],sum[t[x][1]]+da[x]+r[t[x][0]]);
}
void rotate(int x)
{
int y=fa[x],k=lr(x);
t[y][k]=t[x][1-k];if(t[x][1-k]) fa[t[x][1-k]]=y;
fa[x]=fa[y];if(fa[y]) t[fa[y]][lr(y)]=x;
t[x][1-k]=y;fa[y]=x;
update(y);update(x);
}
void splay(int x,int y)
{
xc(x,y);
while(fa[x]!=y)
{
if(fa[fa[x]]!=y)
if(lr(x)==lr(fa[x])) rotate(fa[x]);
else rotate(x);
rotate(x);
}
if(y==0) root=x;
}
int kth(int r,int x)
{
dow2(r);
turn(r);
if(size[t[r][0]]+1==x) return r;
if(size[t[r][0]]>=x) return kth(t[r][0],x);
else return kth(t[r][1],x-size[t[r][0]]-1);
}
void del(int x)
{
rev[x]=0;lz[x]=N;
s[++s[0]]=x;t[fa[x]][lr(x)]=0;fa[x]=0;
if(t[x][0]) del(t[x][0]);
if(t[x][1]) del(t[x][1]);
}
int main()
{
scanf("%d%d",&n,&m);
size[1]=1;lz[1]=N;
fo(i,2,n+1)
{
scanf("%d",&da[i]);
fa[i-1]=i;t[i][0]=i-1;lz[i]=N;
update(i);
}
fa[n+1]=n+2;t[n+2][0]=n+1;lz[n+2]=N;update(n+2);
fa[n+2]=tot=root=n+3;t[n+3][0]=n+2;lz[n+3]=N;update(n+3);
scanf("\n");
for(;m;m--)
{
char ch;
scanf("%c",&ch);
if(ch=='M') scanf("%c",&ch),scanf("%c",&ch);
if(ch=='I')//----------插入
{
int x,c,z;
scanf("NSERT %d %d",&x,&c);
int y=kth(root,x+2);x=kth(root,x+1);
splay(x,0);splay(y,x);
fo(i,1,c)
{
if(s[0]==0) s[++s[0]]=++tot;
int z=s[s[0]--];fa[z]=y;
if(i==1) t[y][0]=z;else t[y][1]=z;
y=z;lz[z]=N;
scanf("%d",&da[z]);
}
for(;y>0;y=fa[y]) update(y);
scanf("\n");
}
if(ch=='D')//----------删除
{
int x,y;scanf("ELETE %d %d\n",&x,&y);
y=kth(root,x+y+1);x=kth(root,x);
splay(x,0);splay(y,x);
int z=t[y][0];
del(z);
update(y);update(x);
}
if(ch=='K')//----------修改
{
int x,y,z;scanf("E-SAME %d %d %d\n",&x,&y,&z);
y=kth(root,x+y+1);x=kth(root,x);
splay(x,0);splay(y,x);
down(t[y][0],z);
splay(t[y][0],0);
}
if(ch=='R')//----------翻转
{
int x,y;scanf("EVERSE %d %d\n",&x,&y);
y=kth(root,x+y+1);x=kth(root,x);
splay(x,0);splay(y,x);
dow1(t[y][0]);
splay(t[y][0],0);
}
if(ch=='G')//----------求和
{
int x,y;scanf("ET-SUM %d %d\n",&x,&y);
y=kth(root,x+y+1);x=kth(root,x);
splay(x,0);splay(y,x);
printf("%d\n",sum[t[y][0]]);
}
if(ch=='X')//----------求最大子序列
{
scanf("-SUM\n");
int x=kth(root,1),y=kth(root,size[root]);
splay(x,0);splay(y,x);
printf("%d\n",d[t[y][0]]);
}
}
}