题目描述
请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)
输入格式:
输入文件的第 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 。
分析
- 插入
根据读入的数据构建一颗Splay(根节点记为rt)
将pos提至root, pos + 1,提至root的右孩子,则只需要将rt插在root的右儿子的左儿子(此时必为空)处即可。 - 删除
处理出要删除的区间[l,r],然后常规操作(略) - 修改 & 翻转
常规操作,找到区间。然后修改并打标记
优先修改标记,修改后无需翻转。
注意附加域的翻转(见下) - 求和
略(好好维护就行) - 最大子序列
由于是树形结构,因此考虑分治的方法
令ls[l,r]为以l为起点的最大子序列,rs[l,r]为以r为终点的最大子序列,ms[l,r]为区间[l,r]的最大子序列
转移方程【对于Splay而言】
—ls[now] = max( ls[lch], sum[lch] + val[now] + ls[rch])
—rs[now] = max(rs[rch], sum[rch] + val[now] + rs[lch])
—ms[now] = max( max( ms[lch], ms[rch] ), rs[lch] + val[now] + ls[rch])
对于区间翻转,除了左右子树交换之外,ls 与 rs 也应该交换
对于特殊情况,若lch/rch不存在,则
ls[lch/rch] = 0, rs[lch/rch] = 0, ms[lch/rch] = -INF - 注意
为了避免边界问题,在首尾插入两个点
注意内存,重复使用节点
代码
#include <cstdio>
#include <cstdlib>
#include <stack>
#include <algorithm>
#define IL inline
#define inf 0x3f3f3f3f
using namespace std;
IL int read()
{
int k = 1, sum = 0;
char c = getchar();
for(; '0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(; '0' <= c && c <= '9'; c = getchar())
sum = sum * 10 + c - '0';
return sum * k;
}
struct node
{
node *father;
node *son[2];
int size;
int val;
int sum;
int ls, rs, ms;
bool upset, cov;
IL node(int v = 0, node *f = 0)
{
father = f;
son[0] = son[1] = 0;
val = ms = sum = v;
size = 1;
ls = rs = (v > 0 ? v : 0);
upset = cov = 0;
}
};
node *root;
stack <node *> stk;
int n;
int num[500005];
IL int max_(int x, int y) { return x > y ? x : y;}
IL int ls(node *p) { return p ? p->ls : 0; }
IL int rs(node *p) { return p ? p->rs : 0; }
IL int ms(node *p) { return p ? p->ms : -inf; }
IL int sum(node *p) { return p ? p->sum : 0; }
IL int size(node *p) { return p ? p->size : 0; }
IL bool son(node *f, node *p) { return f ? (f->son[1] == p) : -1; }
IL void connect(node *f, node *p, bool k)
{
if(!f) root = p; else f->son[k] = p;
if(p) p->father = f;
}
IL void updata(node *p)
{
p->size = size(p->son[0]) + size(p->son[1]) + 1;
p->sum = sum(p->son[0]) + sum(p->son[1]) + p->val;
p->ms = max_( max_(ms(p->son[0]), ms(p->son[1])), p->val + rs(p->son[0]) + ls(p->son[1]));
p->ls = max_(ls(p->son[0]), sum(p->son[0]) + p->val + ls(p->son[1]));
p->rs = max_(rs(p->son[1]), sum(p->son[1]) + p->val + rs(p->son[0]));
}
IL void clean(node *p)
{
if(p->cov)
{
p->cov = p->upset = 0;
node *pp;
for(int i = 0; i < 2; ++ i)
if(p->son[i])
{
pp = p->son[i];
pp->cov = 1;
pp->val = p->val;
pp->sum = pp->size * pp->val;
pp->ls = pp->rs = max_(pp->sum, 0);
pp->ms = ( pp->val > 0 ? pp->sum : pp->val );
}
}else
if(p->upset)
{
p->upset = 0;
node *pp;
for(int i = 0; i < 2; ++ i)
if(p->son[i])
{
pp = p->son[i];
pp->upset ^= 1;
swap(pp->ls, pp->rs);
swap(pp->son[0], pp->son[1]);
}
}
}
IL void rotate(node *p)
{
node *f = p->father, *g = f->father;
bool x = son(f, p), y = !x;
connect(f, p->son[y], x);
connect(g, p, son(g, f));
connect(p, f, y);
updata(f);
}
IL void splay(node *p, node *q)
{
for(node *f, *g; p->father != q;)
{
f = p->father;
g = f->father;
if(g == q) rotate(p); else
{
if(son(g, f) ^ son(f, p))
rotate(p), rotate(p);
else
rotate(f), rotate(p);
}
}
updata(p);
}
IL node *findx(int t)
{
for(node *p = root; t; )
{
clean(p);
if(size(p->son[0]) >= t)
p = p->son[0];
else
if(t - size(p->son[0]) == 1)
{
return p;
}else
{
t -= size(p->son[0]) + 1;
p = p->son[1];
}
}
}
IL node *newnode(int val, node *f)
{
if(stk.empty())
{
return new node(val, f);
}else
{
node *p = stk.top(); stk.pop();
p->father = f;
p->son[0] = p->son[1] = 0;
p->ms = p->val = p->sum = val;
p->size = 1;
p->ls = p->rs = (val > 0 ? val : 0);
p->upset = p->cov = 0;
return p;
}
}
IL void freenode(node *p)
{
stk.push(p);
}
IL node *build(int l, int r, node *f)
{
int mid = (l + r) >> 1;
node *p = newnode(num[mid], f);
if(l != mid) p->son[0] = build(l, mid - 1, p);
if(r != mid) p->son[1] = build(mid + 1, r, p);
updata(p);
return p;
}
IL node *split(int l, int r)
{
node *p = findx(l), *q = findx(r);
splay(p, 0); splay(q ,p);
return q;
}
IL void insert(int l)
{
n = read();
for(int i = 1; i <= n; ++ i) num[i] = read();
node *rt = build(1, n, 0);
node *p = split(l, l + 1);
connect(p, rt, 0);
updata(p); updata(root);
}
IL void recyle(node *p)
{
freenode(p);
if(p->son[0]) recyle(p->son[0]);
if(p->son[1]) recyle(p->son[1]);
}
IL void earse(int l)
{
node *p = split(l - 1, l + read());
recyle(p->son[0]);
p->son[0] = 0;
updata(p); updata(root);
}
IL void modify(int l)
{
node *p = split(l -1, l + read())->son[0];
p->cov = 1;
p->val = read();
p->sum = p->size * p->val;
p->ls = p->rs = max_(p->sum, 0);
p->ms = ( p->val > 0 ? p->sum : p->val );
updata(p->father); updata(root);
}
IL void rever(int l)
{
node *p = split(l - 1, l + read())->son[0];
if(p->cov) return ;
p->upset ^= 1;
if(!p->upset) return ;
swap(p->ls, p->rs);
swap(p->son[0], p->son[1]);
updata(p->father); updata(root);
}
IL int get_sum(int l)
{
int r = l + read();
if(l == r) return 0;
node *p = split(l - 1, r)->son[0];
return p->sum;
}
IL int max_sum()
{
node *p = split(1, size(root))->son[0];
return p->ms;
}
int main()
{
n = read() + 2;
int m = read();
for(int i = 2; i < n; ++ i) num[i] = read();
num[1] = num[n] = -inf;
root = build(1, n, 0);
char c;
for(int x, i = 1; i <= m; ++ i)
{
scanf(" %c",&c);
if(c == 'I')
{
insert(read() + 1);
}else
if(c == 'D')
{
earse(read() + 1);
}else
if(c == 'R')
{
rever(read() + 1);
}else
if(c == 'G')
{
getchar(); getchar(); getchar();
printf("%d\n", get_sum(read() + 1));
}else
if(c == 'M')
{
getchar();
c = getchar();
if(c == 'K')
{
getchar(); getchar();
modify(read() + 1);
}else
if(c == 'X')
{
getchar(); getchar(); getchar(); getchar();
printf("%d\n", max_sum());
}
}
}
}