Description
Input
输入的第11行包含两个数NN和M(M≤20000)M(M≤20000),NN表示初始时数列中数的个数,MM表示要进行的操作数目。
第22行包含NN个数字,描述初始时的数列。
以下MM行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500000500000个数,数列中任何一个数字均在[−1000,1000][−1000,1000]内。
插入的数字总数不超过40000004000000个,输入文件大小不超过20MBytes20MBytes。
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
Source
思路
有几个要注意的地方:
1. MAX-SUM操作的返回值可以为负数!
2. 如果数组大小开4×1064×106是会炸空间的,只能开到5×1055×105,需要加一个垃圾回收函数(就是将删除的树的节点放入栈中,insert时使用栈中的节点)。
3. 求MAX-SUM的值可以参见这一篇博客:最大连续子数列和(by Wolfycz)。
然后就是用BST维护了。
代码
(代码略长,常数略大,勿喷)
数组意义:
fafa,sonson,valval,sizesize应该不需要讲了吧;
icovicov存是否被覆盖,如果为11,那么covcov存覆盖的值;
revrev存是否被反转;
slsl,srsr表示从一个点的子树中左边(或右边)能延伸的最大和;
ff表示子树中最大连续子序列和。
#include <cstdio>
const int maxn=500000;
const int inf=0x3f3f3f3f;
struct stack//方便回收空间(其实也可以用队列)
{
int s[maxn+10],head;
inline int push(int x)
{
++head;
s[head]=x;
return 0;
}
inline int top()
{
return s[head];
}
inline int pop()
{
--head;
return 0;
}
inline int mem()//初始化,使取出的节点开始按照1,2,3...的顺序
{
for(register int i=maxn; i; --i)
{
s[maxn-i+1]=i;
}
head=maxn;
return 0;
}
};
int a[maxn+10];
stack sta;
inline int max(int a,int b)
{
return a>b?a:b;
}
inline int swap(int &a,int &b)
{
int t=a;
a=b;
b=t;
return 0;
}
struct splay_tree
{
int fa[maxn+10],son[2][maxn+10],rev[maxn+10],cov[maxn+10];
int val[maxn+10],sum[maxn+10],size[maxn+10],root,icov[maxn+10];
int sl[maxn+10],sr[maxn+10],f[maxn+10];
inline int t(int x)
{
return son[1][fa[x]]==x;
}
inline int uf(int x)//更新sl,sr和f(这个有点麻烦,自己想想吧)
{
sl[x]=max(son[0][x]?sl[son[0][x]]:-inf,sum[son[0][x]]+val[x]+max(0,sl[son[1][x]]));
sr[x]=max(son[1][x]?sr[son[1][x]]:-inf,sum[son[1][x]]+val[x]+max(0,sr[son[0][x]]));
f[x]=max(max(son[0][x]?f[son[0][x]]:-inf,son[1][x]?f[son[1][x]]:-inf),max(sr[son[0][x]],0)+val[x]+max(sl[son[1][x]],0));
return 0;
}
inline int updata(int x)//更新size,sum,sl,sr和f
{
size[x]=size[son[0][x]]+size[son[1][x]]+1;
sum[x]=val[x]+sum[son[0][x]]+sum[son[1][x]];
uf(x);
return 0;
}
inline int push_rev(int x)//将一个点打上rev标记,同时交换左右儿子
{
rev[x]^=1;
swap(son[0][x],son[1][x]);
swap(sl[x],sr[x]);//左边和右边的最大和需要互换
return 0;
}
inline int push_cover(int x,int v)//将一个点打上cov标记,同时改变val等值
{
icov[x]=1;
cov[x]=v;
val[x]=v;
sum[x]=size[x]*v;
sl[x]=sr[x]=f[x]=max(v,size[x]*v);
return 0;
}
inline int pushdown(int x)//下传标记
{
if(icov[x])
{
if(son[0][x])
{
push_cover(son[0][x],cov[x]);
}
if(son[1][x])
{
push_cover(son[1][x],cov[x]);
}
icov[x]=0;
}
if(rev[x])
{
if(son[0][x])
{
push_rev(son[0][x]);
}
if(son[1][x])
{
push_rev(son[1][x]);
}
rev[x]=0;
}
return 0;
}
inline int rotate(int x)//zig或zag
{
int k=t(x),f=fa[x];
if(fa[f])
{
son[t(f)][fa[f]]=x;
}
fa[x]=fa[f];
if(son[!k][x])
{
fa[son[!k][x]]=f;
}
son[k][f]=son[!k][x];
fa[f]=x;
son[!k][x]=f;
updata(f);
updata(x);
return 0;
}
inline int splay(int x,int c)//旋转x到c的儿子
{
while(fa[x]!=c)
{
int f=fa[x];
if(fa[f]==c)
{
rotate(x);
}
else if(t(f)==t(x))
{
rotate(f);
rotate(x);
}
else
{
rotate(x);
rotate(x);
}
}
if(!c)
{
root=x;
}
return 0;
}
int reuse(int x)//回收以x为根的子树,释放空间
{
if(son[0][x])
{
reuse(son[0][x]);
}
if(son[1][x])
{
reuse(son[1][x]);
}
sta.push(x);
return 0;
}
inline int getkth(int k)//寻找第k大
{
int now=root;
while(now)
{
pushdown(now);//这里用到了pushdown,接下来就只需要调用getkth完成pushdown
if(size[son[0][now]]+1==k)
{
return now;
}
else if(size[son[0][now]]+1<k)
{
k-=size[son[0][now]]+1;
now=son[1][now];
}
else
{
now=son[0][now];
}
}
return 0;
}
inline int insert(int l,int r)//将a数组中l到r的区间建立成一棵树,并返回这棵树的根
{
int x=sta.top(),mid=(l+r)>>1;
sta.pop();
val[x]=a[mid];
icov[x]=rev[x]=0;
sl[x]=sr[x]=f[x]=max(0,a[mid]);
size[x]=r-l+1;
if(l<=mid-1)
{
son[0][x]=insert(l,mid-1);
fa[son[0][x]]=x;
}
else
{
son[0][x]=0;
}
if(mid+1<=r)
{
son[1][x]=insert(mid+1,r);
fa[son[1][x]]=x;
}
else
{
son[1][x]=0;
}
updata(x);
return x;
}
inline int ins(int pos,int tot)//在pos后插入a[1-tot],注意直接建成一条链会TLE,必须二分建树
{
if(!root)
{
root=insert(1,tot);
fa[root]=0;
return 0;
}
else if(!pos)
{
int now=getkth(1);
splay(now,0);
son[0][now]=insert(1,tot);
fa[son[0][now]]=now;
updata(root);
return 0;
}
else if(pos==size[root])
{
int now=getkth(size[root]);
splay(now,0);
son[1][now]=insert(1,tot);
fa[son[1][now]]=now;
updata(root);
return 0;
}
else
{
int x=getkth(pos);
splay(x,0);
int y=getkth(pos+1);
splay(y,x);
son[0][y]=insert(1,tot);
fa[son[0][y]]=y;
updata(y);
updata(x);
return 0;
}
}
inline int del(int l,int r)//删去l-r节点
{
if(l==1)
{
if(r==size[root])
{
reuse(root);
root=0;
}
else
{
int x=getkth(r+1);
splay(x,0);
reuse(son[0][x]);
son[0][x]=0;
updata(x);
}
}
else
{
int x=getkth(l-1);
splay(x,0);
if(r==size[root])
{
reuse(son[1][x]);
son[1][x]=0;
}
else
{
int y=getkth(r+1);
splay(y,x);
reuse(son[0][y]);
son[0][y]=0;
updata(y);
}
updata(x);
}
return 0;
}
inline int reverse(int l,int r)//反转l-r节点
{
if(l==1)
{
if(r==size[root])
{
push_rev(root);
}
else
{
int x=getkth(r+1);
splay(x,0);
push_rev(son[0][x]);
uf(x);
}
}
else
{
int x=getkth(l-1);
splay(x,0);
if(r==size[root])
{
push_rev(son[1][x]);
}
else
{
int y=getkth(r+1);
splay(y,x);
push_rev(son[0][y]);
uf(y);
}
uf(x);
}
return 0;
}
inline int getsum(int l,int r)//返回l-r的连加和
{
if(l==1)
{
if(r==size[root])
{
return sum[root];
}
else
{
int x=getkth(r+1);
splay(x,0);
return sum[son[0][x]];
}
}
else
{
int x=getkth(l-1);
splay(x,0);
if(r==size[root])
{
return sum[son[1][x]];
}
else
{
int y=getkth(r+1);
splay(y,x);
return sum[son[0][y]];
}
}
}
inline int cover(int l,int r,int v)//将l-r覆盖为v
{
if(l==1)
{
if(r==size[root])
{
push_cover(root,v);
}
else
{
int x=getkth(r+1);
splay(x,0);
push_cover(son[0][x],v);
updata(x);
}
}
else
{
int x=getkth(l-1);
splay(x,0);
if(r==size[root])
{
push_cover(son[1][x],v);
}
else
{
int y=getkth(r+1);
splay(y,x);
push_cover(son[0][y],v);
updata(y);
}
updata(x);
}
return 0;
}
inline int getmax()//返回最大连续子序列和
{
return f[root];
}
};
splay_tree st;
int n,m,x,y,z;
char s[10];
int main()
{
sta.mem();
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; ++i)
{
scanf("%d",&a[i]);
}
st.ins(0,n);//这里相当于省去了开始的build步骤
while(m--)
{
scanf("%s",s);
if(s[0]=='I')
{
scanf("%d%d",&x,&y);
for(register int i=1; i<=y; ++i)
{
scanf("%d",&a[i]);
}
st.ins(x,y);
}
else if(s[0]=='D')
{
scanf("%d%d",&x,&y);
st.del(x,x+y-1);
}
else if(s[0]=='M')
{
if(s[2]=='K')
{
scanf("%d%d%d",&x,&y,&z);
st.cover(x,x+y-1,z);
}
else
{
printf("%d\n",st.getmax());
}
}
else if(s[0]=='R')
{
scanf("%d%d",&x,&y);
st.reverse(x,x+y-1);
}
else
{
scanf("%d%d",&x,&y);
printf("%d\n",st.getsum(x,x+y-1));
}
}
return 0;
}
(代码好难打啊……)