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 求出当前数列中和最大的一段子列,并输出最大和
你可以认为在任何时刻,数列中至少有1个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
100%的数据中,任何时刻数列中最多含有500 000个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。
Analysis
本蒟蒻暂时只会打splay,这题就是用splay做的
实现细节:
- 由于插入删除的数字可能很多,所以要开一个栈把删除的节点存起来,下次插入的时候再利用,回收空间
- 本题中为了实现MAX-SUM操作,需对于每个点记录lx,rx,mx,分别表示从中间向左,向右能延伸的最大和,整个区间的最大和
- 区间赋值操作的tag不能初始化为0,要为INF
- 区间翻转操作的tag打标记的时候是^1而非=1
- 反转操作一定要先直接交换两个子树及相关信息(本题中的左右子树相关信息为lx,rx),再打tag标记
- 对于所有的修改操作,做完都要update(我简单粗暴将该点splay到根)
Code
#include<cstdio>
#include<stack>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=500010;
int n,tot,root,top,sta[N],size[N],f[N],a[N][2],bz[N],tag[N];
int b[N],sum[N],key[N],lx[N],rx[N],mx[N];
stack<int> q;
int pd(int x)
{
return x==a[f[x]][1];
}
void update(int x)
{
int ls=a[x][0],rs=a[x][1];
size[x]=1+size[ls]+size[rs];
sum[x]=key[x]+sum[ls]+sum[rs];
lx[x]=max(lx[ls],sum[ls]+key[x]+lx[rs]);
rx[x]=max(rx[rs],sum[rs]+key[x]+rx[ls]);
mx[x]=rx[ls]+key[x]+lx[rs];
if(ls) mx[x]=max(mx[x],mx[ls]);
if(rs) mx[x]=max(mx[x],mx[rs]);
}
void change(int x,int z)
{
if(!x) return;
sum[x]=size[x]*z,key[x]=bz[x]=z;
if(z>0) lx[x]=rx[x]=mx[x]=size[x]*z;
else lx[x]=rx[x]=0,mx[x]=z;
}
void turn(int x)
{
if(!x) return;
swap(a[x][0],a[x][1]);
swap(lx[x],rx[x]);
tag[x]^=1;
}
void down(int x)
{
if(!x) return;
if(tag[x])
{
turn(a[x][0]),turn(a[x][1]);
tag[x]=0;
}
if(bz[x]!=N)
{
change(a[x][0],bz[x]),change(a[x][1],bz[x]);
bz[x]=N;
}
}
void remove(int x,int y)
{
for(;x!=y;x=f[x]) q.push(x);
while(!q.empty())
{
down(q.top());q.pop();
}
}
void rotate(int x)
{
int y=f[x],z=pd(x);
a[y][z]=a[x][1-z];
if(a[x][1-z]) f[a[x][1-z]]=y;
f[x]=f[y];
if(f[y]) a[f[y]][pd(y)]=x;
a[x][1-z]=y,f[y]=x;
update(y);
}
void splay(int x,int y)
{
remove(x,y);
if(!y) root=x;
while(f[x]!=y)
{
if(f[f[x]]!=y)
if(pd(x)==pd(f[x])) rotate(f[x]);
else rotate(x);
rotate(x);
}
update(x);
}
void del(int x)
{
if(!x) return;
sta[++top]=x;
del(a[x][0]);del(a[x][1]);
f[x]=a[x][0]=a[x][1]=0;
}
int newnode(int z)
{
int x;
if(top) x=sta[top--];
else x=++tot;
size[x]=1,key[x]=sum[x]=mx[x]=z,lx[x]=rx[x]=max(z,0);
tag[x]=0,bz[x]=N;
return x;
}
void build(int &x,int l,int r,int fa)
{
if(l>r) return;
int mid=(l+r)>>1;
x=newnode(b[mid]);
f[x]=fa;
if(l==r) return;
build(a[x][0],l,mid-1,x),build(a[x][1],mid+1,r,x);
update(x);
}
int kth(int x,int k)
{
down(x);
if(size[a[x][0]]+1==k) return x;
if(k>size[a[x][0]]) return kth(a[x][1],k-size[a[x][0]]-1);
else return kth(a[x][0],k);
}
int split(int x,int y)
{
x=kth(root,x),y=kth(root,y+2);
splay(x,0),splay(y,x);
return a[y][0];
}
int main()
{
freopen("sequence10.in","r",stdin);
freopen("2413.out","w",stdout);
int _,x,y,z,p,m;
char ch;
scanf("%d %d",&n,&_);
fo(i,2,n+1) scanf("%d",&b[i]);
build(root,1,n+2,0);
scanf("\n");
for(;_;_--)
{
scanf("%c",&ch);
if(ch=='I')
{
scanf("NSERT %d %d",&p,&m);
fo(i,1,m) scanf("%d",&b[i]);
x=kth(root,p+1),y=kth(root,p+2);
splay(x,0),splay(y,x);
build(a[y][0],1,m,y);
splay(a[y][0],0);
}
if(ch=='D')
{
scanf("ELETE %d %d",&x,&z);y=x+z-1;
x=split(x,y);
y=f[x];
a[y][pd(x)]=0;
del(x);
splay(y,0);
}
if(ch=='M')
{
scanf("%c",&ch);scanf("%c",&ch);
if(ch=='K')
{
scanf("E-SAME %d %d %d",&x,&y,&z);y=x+y-1;
x=split(x,y);
change(x,z);
splay(x,0);
}
else
{
scanf("-SUM");
x=kth(root,1),y=kth(root,size[root]);
splay(x,0),splay(y,x);
printf("%d\n",mx[a[y][0]]);
}
}
if(ch=='R')
{
scanf("EVERSE %d %d",&x,&z);y=x+z-1;
x=split(x,y);
turn(x);
splay(x,0);
}
if(ch=='G')
{
scanf("ET-SUM %d %d",&x,&z);y=x+z-1;
x=split(x,y);
printf("%d\n",sum[x]);
}
scanf("\n");
}
return 0;
}