Description
Input
输入的第
1
1
行包含两个数和
M
M
,
N
N
表示初始时数列中数的个数,表示要进行的操作数目.
第
2
2
行包含个数字,描述初始时的数列.
以下
M
M
行,每行一条命令,格式参见问题描述中的表格.
任何时刻数列中最多含有个数,数列中任何一个数字均在
[−103,103]
[
−
10
3
,
10
3
]
内.
插入的数字总数不超过
4∗106
4
∗
10
6
个,输入文件大小不超过
20MB
20
M
B
Output
对于输入数据中的
GET−SUM
G
E
T
−
S
U
M
和
MAX−SUM
M
A
X
−
S
U
M
操作,向输出文件依次打印结果,每个答案(数字)占一行.
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
Data Size & Hint
你可以认为在任何时刻,数列中至少有
1
1
个数
输入数据一定是正确的,即指定位置的数在数列中一定存在
的数据中,任何时刻数列中最多含有
3∗104
3
∗
10
4
个数
100%
100
%
的数据中,任何时刻数列中最多含有
5∗105
5
∗
10
5
个数
100%
100
%
的数据中,任何时刻数列中任何一个数字均在
[−103,103]
[
−
10
3
,
10
3
]
内
100%
100
%
的数据中,
M≤2∗104
M
≤
2
∗
10
4
,插入的数字总数不超过
4∗106
4
∗
10
6
Solution
这个题目的操作很多,也很杂,在做题时推荐先想好操作之间的关系,然后一个一个去解决
预备工作
Q1 如何建树?
考虑到后面需要区间插入,所以直接区间离线建树,再将根节点插入原序列中
并且建树时插入前后两个哨兵节点,方便后面提取区间进行操作
Q2 需要维护些什么?
显然的,翻转标记 (rev) ( r e v ) 和区间修改标记 (tag) ( t a g ) 是必须要有的,第6个操作暂时先不考虑
1. INSERT
基操
∗1
∗
1
由于是将一段数插入到某点后方
先将其建成一棵小平衡树
然后将插入位置提取出来
将根节点作为插入点的右儿子即可
2. DELETE
基操
∗2
∗
2
直接将区间提取出来后将其与父亲节点联系断开即可
由于总插入数量可能达到
4∗106
4
∗
10
6
,所以将删除的点编号回收
(recycle)
(
r
e
c
y
c
l
e
)
以供下次插入时使用
3. MAKE-SAME
基操
∗3
∗
3
将区间提取出来,打上标记,解决
4. REVERSE
基操
∗4
∗
4
将区间提取出来,打上标记,解决
5. GET-SUM
基操
∗5
∗
5
考虑多维护一个数组
sum
s
u
m
,表示其当前节点为根节点构成的子树的总和
这个标记会与前面的
INSERT,DELETE,MAKE−SAME
I
N
S
E
R
T
,
D
E
L
E
T
E
,
M
A
K
E
−
S
A
M
E
进行联动,在操作时记得维护就好
6. MAX-SUM
非基操,独秀同学你可以上来了
一般来说,维护一个数列的最值可以通过枚举区间的方式
Splay
S
p
l
a
y
的性质决定了他非常的适合使用这样的方式
每棵子树代表的区间,维护区间
1. 左端点开始的最大子序列
lx
l
x
2. 右端点开始的最大子序列
rx
r
x
3. 区间最大子序列
mx
m
x
很容易的就能写
update
u
p
d
a
t
e
的方程
通过枚举区间选不选 x x ,统计出答案,然后一路合并上去,最终就是总区间最大子序列
这个标记会与前面的
INSERT,DELETE,MAKE−SAME,REVERSE
I
N
S
E
R
T
,
D
E
L
E
T
E
,
M
A
K
E
−
S
A
M
E
,
R
E
V
E
R
S
E
进行联动
INSERT
I
N
S
E
R
T
和
DELETE
D
E
L
E
T
E
比较简单,不表
当
MAKE−SAME
M
A
K
E
−
S
A
M
E
时
若当前节点小于
0
0
,那么其(我选择不选)
mx[x]=key[x]
m
x
[
x
]
=
k
e
y
[
x
]
(只选一个使其尽量大)
若当前节点大于等于
0
0
,那么其
当
REVERSE
R
E
V
E
R
S
E
时
直接调换
lx[x],rx[x]
l
x
[
x
]
,
r
x
[
x
]
即可
这个题目难度不是很大,但是码量惊人(对本蒟来说)
能让人调到心态崩溃
所以,当你实在过不了的时候
重写吧!
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define L ch[x][0]
#define R ch[x][1]
#define mid ((l+r)>>1)
const int N = 500010;
const int INF = 2100000000;
int a[N];
queue <int> q;
struct SPLAY {
int f[N],ch[N][2],key[N],siz[N],rt,cnt;
int lx[N],rx[N],mx[N],sum[N];
bool tag[N],rev[N];
void Rev(int x) {swap(L,R);swap(lx[x],rx[x]);}
void update(int x) {
sum[x]=sum[L]+sum[R]+key[x];
siz[x]=1+siz[L]+siz[R];
mx[x]=max(mx[L],max(mx[R],rx[L]+key[x]+lx[R]));
lx[x]=max(lx[L],sum[L]+key[x]+lx[R]);
rx[x]=max(rx[R],sum[R]+key[x]+rx[L]);
}
void pushdown(int x) {
if(tag[x]) {
rev[x]=tag[x]=0;
if(L) {tag[L]=1;key[L]=key[x];sum[L]=siz[L]*key[x];}
if(R) {tag[R]=1;key[R]=key[x];sum[R]=siz[R]*key[x];}
if(key[x]>=0) {
if(L) lx[L]=rx[L]=mx[L]=sum[L];
if(R) lx[R]=rx[R]=mx[R]=sum[R];
}
else {
if(L) {lx[L]=rx[L]=0;mx[L]=key[L];}
if(R) {lx[R]=rx[R]=0;mx[R]=key[R];}
}
}
if(rev[x]) {
rev[x]=0;rev[L]^=1;rev[R]^=1;
Rev(L);Rev(R);
}
}
bool get(int x) {return ch[f[x]][1]==x;}
void rotate(int x) {
int old=f[x],oldf=f[old],w=get(x);
pushdown(old);pushdown(x);
ch[old][w]=ch[x][w^1];ch[x][w^1]=old;
f[old]=x;f[ch[old][w]]=old;f[x]=oldf;
if(oldf) ch[oldf][ch[oldf][1]==old]=x;
update(old);update(x);
}
void splay(int x,int tar) {
for(int fa;(fa=f[x])!=tar;rotate(x))
if(f[fa]!=tar)
rotate(get(x)==get(fa)?fa:x);
if(!tar) rt=x;
}
int findbyrank(int rank) {
int x=rt;
while(1) {
pushdown(x);
if(siz[L]>=rank) {x=L;}
else {
rank-=siz[L]+1;
if(!rank) return x;
x=R;
}
}
}
void clear(int x) {L=R=f[x]=lx[x]=rx[x]=mx[x]=tag[x]=rev[x]=key[x]=siz[x]=sum[x]=0;}
void recycle(int x) {
if(L) recycle(L);
if(R) recycle(R);
q.push(x);
clear(x);
}
int build(int l,int r,int fa) {
if(l>r) return 0;
int x;
if(!q.empty()) {x=q.front();q.pop();}
else {x=++cnt;}
f[x]=fa;key[x]=a[mid];siz[x]=1;sum[x]=key[x];
lx[x]=rx[x]=max(key[x],0);mx[x]=key[x];
if(l<mid) L=build(l,mid-1,x);
if(r>mid) R=build(mid+1,r,x);
update(x);
return x;
}
void insert(int pos,int tot) {
int l=findbyrank(pos+1),r=findbyrank(pos+2);
splay(r,0);splay(l,r);
int new_node=build(1,tot,l);
ch[l][1]=new_node;
update(l);update(r);
splay(new_node,0);
}
void del(int pos,int tot) {
int l=findbyrank(pos),r=findbyrank(pos+tot+1);
splay(l,0);splay(r,l);
recycle(ch[r][0]);
ch[r][0]=0;
update(r);update(l);
}
void change(int pos,int tot,int p) {
int l=findbyrank(pos),r=findbyrank(pos+tot+1);
splay(l,0);splay(r,l);
key[ch[r][0]]=p;
tag[ch[r][0]]=1;
sum[ch[r][0]]=siz[ch[r][0]]*p;
if(key[ch[r][0]]>=0) {lx[ch[r][0]]=rx[ch[r][0]]=mx[ch[r][0]]=sum[ch[r][0]];}
else {lx[ch[r][0]]=rx[ch[r][0]]=0;mx[ch[r][0]]=key[ch[r][0]];}
update(r);update(l);
}
void reserve(int pos,int tot) {
int l=findbyrank(pos),r=findbyrank(pos+tot+1);
splay(l,0);splay(r,l);
Rev(ch[r][0]);
rev[ch[r][0]]^=1;
update(r);update(l);
}
void get(int pos,int tot) {
int l=findbyrank(pos),r=findbyrank(pos+tot+1);
splay(l,0);splay(r,l);
printf("%d\n",sum[ch[r][0]]);
}
void query() {printf("%d\n",mx[rt]);}
void print(int x) {
if(!x) return;
pushdown(x);
print(L);
printf("%d ",key[x]);
print(R);
}
}s;
int n,m;
char str[10];
int read();
void init();
int main() {
init();
for(int i=1;i<=m;++i) {
scanf("%s",str);
if(str[0]=='I' && str[1]=='N') {
int pos=read(),tot=read();
for(int i=1;i<=tot;++i) a[i]=read();
s.insert(pos,tot);
}
else if(str[0]=='D' && str[1]=='E') {
int pos=read(),tot=read();
if(tot==0) continue;
s.del(pos,tot);
}
else if(str[0]=='M' && str[1]=='A' && str[2]=='K') {
int pos=read(),tot=read(),p=read();
if(tot==0) continue;
s.change(pos,tot,p);
}
else if(str[0]=='R' && str[1]=='E') {
int pos=read(),tot=read();
if(tot==0) continue;
s.reserve(pos,tot);
}
else if(str[0]=='G' && str[1]=='E') {
int pos=read(),tot=read();
if(tot==0) puts("0");
else s.get(pos,tot);
}
else s.query();
}
return 0;
}
int read() {
int _ans=0,_flag=1;
char _ch=getchar();
while((_ch != '-') && (_ch > '9' || _ch < '0')) _ch=getchar();
if(_ch == '-') {_flag = -1;_ch = getchar();}
while(_ch >= '0' && _ch <= '9') {_ans=_ans*10+_ch-'0';_ch=getchar();}
return _ans*_flag;
}
void init() {
n=read();m=read();
s.mx[0]=-INF;
a[1]=-INF;a[n+2]=-INF;
for(int i=2;i<=n+1;++i) a[i]=read();
s.rt=s.build(1,n+2,0);
}