输入格式
输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M 表示要进行的操作数目。 第 2 行包含 N 个数字,描述初始时的数列。 以下 M 行,每行一条命令,格式参见问题描述中的表格
输出格式
对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结 果,每个答案(数字)占一行。
你可以认为在任何时刻,数列中至少有 1 个数。
输入数据一定是正确的,即指定位置的数在数列中一定存在。
100%的数据中,任何时刻数列中最多含有 500 000 个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 。
题解
有了上面的铺垫,其实这些操作都可以解决了。
以下的根不做特殊说明都指区间代表子树的根。
只是有点小细节需要注意:
插入时要先把插入序列建splay,不然一个一个插入会超时。建splay时需要特判叶子节点维护一些信息,对于lmax和rmax需要将val和0取max,因为在父亲节点更新lmax是可能为左区间+父亲节点本身,如果右区间lmax直接取val,就可能取不到这种情况,或许比较三种情况可以解决这个问题,但是很麻烦不是吗。
删除的时候,把这段区间提取出来删除即可。不过因为空间原因需要回收节点编号,所以需要遍历这棵子树回收,用队列装编号。最多插入4e6个数,所以最多遍历4e6个点。
区间覆盖的时候,提取区间后,在根打上覆盖标记,维护节点信息:注意如果val是负数最大子段和赋成val。
翻转提取区间,在根打上翻转标记,将lmax和rmax交换。
求和提取区间输出根的sum即可。
这道题的最大子段和是整个序列的,其实降低了一点难度,直接输出整颗splay的根的最大子段和即可。
下传在find里面。
建初始序列时要在收尾插入两个最小值,因为最大值在求最大子段和会有影响。
还有对于0号节点的最大子段和赋最小值,因为一些没有儿子的点更新信息会用到。
#include<bits/stdc++.h> using namespace std; const int oo=1000000; const int maxn=500005; int n,m; int a[maxn],num,id[maxn],root; queue<int> q; struct Splay{ int s[2],fa,size,tag,cover;//tag:当前节点是否需要交换儿子 int val,sum,dat,lmax,rmax; }tr[maxn]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x= f ? -x : x ; } int max(int x,int y){return x>y ? x : y ;} void update(Splay &ret,Splay lx,Splay ry){ ret.size=lx.size+ry.size+1; ret.sum=lx.sum+ry.sum+ret.val; ret.lmax=max(lx.lmax,lx.sum+ret.val+ry.lmax); ret.rmax=max(ry.rmax,ry.sum+ret.val+lx.rmax); ret.dat=max(max(lx.dat,ry.dat),lx.rmax+ret.val+ry.lmax);//给0赋值防止了出事 //printf("-%d-",ret.val); } void update(int x){ update(tr[x],tr[tr[x].s[0]],tr[tr[x].s[1]]); } int build(int l,int r,int f){ //printf("%d %d ",l,r); if(l>r) return 0; int mid=(l+r)>>1,now=id[mid]; tr[now].fa=f; tr[now].val=a[mid]; tr[now].cover=oo; if(l==r){ tr[now].size=1; tr[now].sum=tr[now].val; tr[now].lmax=tr[now].rmax=max(0,tr[now].val); tr[now].dat=tr[now].val;//记得赋值 return now; } tr[now].s[0]=build(l,mid-1,now); tr[now].s[1]=build(mid+1,r,now); update(now); return now; } void put_cover(int x,int val){ if(!x) return ; tr[x].val=tr[x].cover=val; tr[x].sum=val*tr[x].size; tr[x].lmax=tr[x].rmax= val>=0 ? tr[x].sum : 0; tr[x].dat= val>=0 ? tr[x].sum : val;//必须选取至少一个元素 } void put_tag(int x){ if(!x) return ; tr[x].tag^=1; swap(tr[x].s[0],tr[x].s[1]); swap(tr[x].lmax,tr[x].rmax); } void push_down(int x){ if(tr[x].cover!=oo){ put_cover(tr[x].s[0],tr[x].cover); put_cover(tr[x].s[1],tr[x].cover); tr[x].cover=oo; } if(tr[x].tag){ put_tag(tr[x].s[0]); put_tag(tr[x].s[1]); tr[x].tag=0; } } void debug(int x){ push_down(x); if(tr[x].s[0]) debug(tr[x].s[0]); printf("%d ",tr[x].val); if(tr[x].s[1]) debug(tr[x].s[1]); } int find(int k){ int now=root; while(1){ //printf("%d %d ",k,now); push_down(now); if(tr[tr[now].s[0]].size>=k) {now=tr[now].s[0];continue;} k-=tr[tr[now].s[0]].size; if(k==1) return now; k--; now=tr[now].s[1]; } } int get(int x){ return tr[tr[x].fa].s[1]==x; } void connect(int x,int y,int d){ tr[y].s[d]=x; tr[x].fa=y; } void rotate(int x){ int f=tr[x].fa,ff=tr[f].fa; int d1=get(x),d2=get(f); int cs=tr[x].s[d1^1]; connect(x,ff,d2); connect(f,x,d1^1); connect(cs,f,d1); update(f); update(x); } void splay(int x,int go){ if(go==root) root=x; go=tr[go].fa; while(tr[x].fa!=go){ int f=tr[x].fa; if(tr[f].fa==go) rotate(x); else if(get(x)==get(f)) {rotate(f);rotate(x);} else {rotate(x);rotate(x);} } } void insert(){ int pos,tot; read(pos);read(tot);n+=tot; for(int i=1;i<=tot;i++){ read(a[i]); if(!q.empty()) id[i]=q.front(),q.pop(); else id[i]=++num; } int nowroot=build(1,tot,0); int x=find(pos+1),y=find(pos+2); splay(x,root); splay(y,tr[x].s[1]); tr[nowroot].fa=y; tr[y].s[0]=nowroot; update(y); update(x); } void clean(int x){ tr[x]=(Splay){{0,0},0,0,0,oo,0,0,0,0,0}; } void recycle(int x){ if(tr[x].s[0]) recycle(tr[x].s[0]); if(tr[x].s[1]) recycle(tr[x].s[1]); clean(x); q.push(x); } void dele(){ int pos,tot; read(pos);read(tot);n-=tot; int x=find(pos),y=find(pos+tot+1); splay(x,root); splay(y,tr[x].s[1]); recycle(tr[y].s[0]); tr[y].s[0]=0; update(y); update(x); } void modify(){ int pos,tot; int val; read(pos);read(tot);read(val); int x=find(pos),y=find(pos+tot+1); splay(x,root); splay(y,tr[x].s[1]); put_cover(tr[y].s[0],val); update(y); update(x); } void reverse(){ int pos,tot; read(pos);read(tot); int x=find(pos),y=find(pos+tot+1); splay(x,root); splay(y,tr[x].s[1]); put_tag(tr[y].s[0]); update(y); update(x); } int querysum(){ int pos,tot; read(pos);read(tot); int x=find(pos),y=find(pos+tot+1); splay(x,root); splay(y,tr[x].s[1]); //printf("%d %d ",x,y); //printf("%d ",tr[tr[y].s[0]].size); //putchar(10); //debug(tr[y].s[0]); //putchar(10); return tr[tr[y].s[0]].sum; } int querydat(){ int x=find(1),y=find(n); splay(x,root); splay(y,tr[x].s[1]); return tr[tr[y].s[0]].dat; } int main(){ read(n);read(m); tr[0].dat=a[1]=a[n+2]=-oo;//给零赋值,不然建树会出锅 for(int i=1;i<=n;i++) read(a[i+1]); for(int i=1;i<=n+2;i++) id[i]=++num; n=n+2; root=build(1,n,0); for(int i=1;i<=m;i++){ char opt[15]; scanf("%s",opt); if(opt[2]=='S') insert(); else if(opt[2]=='L') dele(); else if(opt[2]=='K') modify(); else if(opt[2]=='V') reverse(); else if(opt[2]=='T') printf("%d ",querysum()); else printf("%d ",tr[root].dat); //putchar(10); //debug(root); //putchar(10); } }