P3884 NOI2005维修数列
问题描述
输入格式
第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
输出格式
对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。
样例输入
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
样例输出
-1
10
1
10
提示
你可以认为在任何时刻,数列中至少有 1 个数。 输入数据一定是正确的,即指定位置的数在数列中一定存在。
50%的数据中,任何时刻数列中最多含有 30 000 个数; 100%的数据中,任何时刻数列中最多含有 500 000 个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。 100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 个,输入文件 大小不超过 20MBytes。
Splay模板题,修改和翻转用lazy,维护区间和,考虑如何维护最大区间和,用类似线段树的方法解决即可。
注意当儿子为0时要特别小心。
代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 8000005
#define max(a,b) ((a>b)?(a):(b))
using namespace std;
const int Inf=99999999;
int n,m,A[N],L,R;
int tot,rt,ls[N],rs[N],fa[N],si[N],v[N],lazy1[N],lazy2[N],lmax[N],rmax[N],Max[N],sum[N];
int GM(int x,int y,int z)
{
if(x>=y&&x>=z)return x;
if(y>=z)return y;
return z;
}
void MT(int p)
{
lmax[p]=GM(lmax[ls[p]],sum[ls[p]]+v[p],sum[ls[p]]+v[p]+lmax[rs[p]]);
rmax[p]=GM(rmax[rs[p]],sum[rs[p]]+v[p],sum[rs[p]]+v[p]+rmax[ls[p]]);
Max[p]=GM(Max[ls[p]],Max[rs[p]],max(0,lmax[rs[p]])+max(0,rmax[ls[p]])+v[p]);
sum[p]=sum[ls[p]]+sum[rs[p]]+v[p];
si[p]=si[ls[p]]+si[rs[p]]+1;
}
void PD(int p)
{
if(lazy1[p])
{
swap(ls[ls[p]],rs[ls[p]]);
swap(lmax[ls[p]],rmax[ls[p]]);
swap(ls[rs[p]],rs[rs[p]]);
swap(lmax[rs[p]],rmax[rs[p]]);
lazy1[ls[p]]^=1;
lazy1[rs[p]]^=1;
}
if(lazy2[p]!=Inf)
{
v[ls[p]]=v[rs[p]]=lazy2[p];
sum[ls[p]]=lazy2[p]*si[ls[p]];
sum[rs[p]]=lazy2[p]*si[rs[p]];
lmax[ls[p]]=rmax[ls[p]]=Max[ls[p]]=lazy2[p]>0?lazy2[p]*si[ls[p]]:lazy2[p];
lmax[rs[p]]=rmax[rs[p]]=Max[rs[p]]=lazy2[p]>0?lazy2[p]*si[rs[p]]:lazy2[p];
lazy2[ls[p]]=lazy2[rs[p]]=lazy2[p];
}
lazy1[p]=0;lazy2[p]=Inf;
}
void Zig(int x)
{
int y=fa[x],z=fa[y];
if(y==ls[z])ls[z]=x;else rs[z]=x;fa[x]=z;
ls[y]=rs[x];fa[rs[x]]=y;
rs[x]=y;fa[y]=x;
MT(y);MT(x);
}
void Zag(int x)
{
int y=fa[x],z=fa[y];
if(y==ls[z])ls[z]=x;else rs[z]=x;fa[x]=z;
rs[y]=ls[x];fa[ls[x]]=y;
ls[x]=y;fa[y]=x;
MT(y);MT(x);
}
void Splay(int x,int t)
{
int y,z;
while(fa[x]!=t)
{
y=fa[x];z=fa[y];
if(z)PD(z);
if(y)PD(y);
if(x)PD(x);
if(z!=t)
{
if(y==ls[z])
{
if(x==ls[y])Zig(y),Zig(x);
else Zag(x),Zig(x);
}
else
{
if(x==rs[y])Zag(y),Zag(x);
else Zig(x),Zag(x);
}
}
else if(x==ls[y])Zig(x);else Zag(x);
}
if(!t)rt=x;
}
int BT(int x,int y)
{
if(x>y)return 0;
int p=++tot;
lazy2[p]=Inf;
if(x==y&&x==0)L=p;
if(x==y&&x==n+1)R=p;
if(x<y)
{
int mid=x+y>>1;
if(mid==0)L=p;
if(mid==n+1)R=p;
v[p]=A[mid];
ls[p]=BT(x,mid-1);
rs[p]=BT(mid+1,y);
fa[ls[p]]=p;
fa[rs[p]]=p;
MT(p);
}
else v[p]=sum[p]=lmax[p]=rmax[p]=Max[p]=A[x],si[p]=1;
return p;
}
int Find(int k)
{
int p=rt;
while(p)
{
PD(p);
if(si[ls[p]]+1==k)return p;
if(si[ls[p]]>=k)p=ls[p];
else k-=si[ls[p]]+1,p=rs[p];
}
return p;
}
void INS()
{
int i,x,y,a,b;
scanf("%d%d",&x,&y);
for(i=1;i<=y;i++)scanf("%d",&A[i]);
a=Find(x+1);b=Find(x+2);
Splay(a,0);Splay(b,rt);
tot++;
v[tot]=sum[tot]=lmax[tot]=rmax[tot]=Max[tot]=A[1];
lazy2[tot]=Inf;si[tot]=1;
for(i=2;i<=y;i++)
{
tot++;
v[tot]=A[i];
lazy2[tot]=Inf;
ls[tot]=tot-1;
fa[tot-1]=tot;
MT(tot);
}
fa[tot]=b;ls[b]=tot;MT(b);MT(a);
}
void DEL()
{
int x,y,a,b;
scanf("%d%d",&x,&y);
a=Find(x);b=Find(x+y+1);
Splay(a,0);Splay(b,rt);
fa[ls[rs[rt]]]=0;
ls[rs[rt]]=0;
MT(rs[rt]);
MT(rt);
}
void CHA()
{
int x,y,z,a,b,p;
scanf("%d%d%d",&x,&y,&z);
a=Find(x);b=Find(x+y+1);
Splay(a,0);Splay(b,rt);
p=ls[rs[rt]];
lazy2[p]=z;
v[p]=z;sum[p]=z*si[p];
lmax[p]=rmax[p]=Max[p]=z>0?z*si[p]:z;
MT(rs[rt]);
MT(rt);
}
void REV()
{
int x,y,a,b,p;
scanf("%d%d",&x,&y);
a=Find(x);b=Find(x+y+1);
Splay(a,0);Splay(b,rt);
p=ls[rs[rt]];
lazy1[p]^=1;
swap(ls[p],rs[p]);
swap(lmax[p],rmax[p]);
MT(rs[rt]);
MT(rt);
}
void SUM()
{
int x,y,a,b;
scanf("%d%d",&x,&y);
a=Find(x);b=Find(x+y+1);
Splay(a,0);Splay(b,rt);
printf("%d\n",sum[ls[rs[rt]]]);
}
void MAX()
{
Splay(L,0);Splay(R,rt);
printf("%d\n",Max[ls[rs[rt]]]);
}
int main()
{
int i,x,y,z;char s[15];
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&A[i]);
rt=BT(0,n+1);
while(m--)
{
scanf("%s",s);
if(s[2]=='S')INS();
if(s[2]=='L')DEL();
if(s[2]=='K')CHA();
if(s[2]=='V')REV();
if(s[2]=='T')SUM();
if(s[2]=='X')MAX();
}
}