P2042 [NOI2005]维护数列
毒瘤模板题!!!!
这道题看到什么维护序列的,肯定就是用数据结构的。
这个东西叫你做下面的事情:
首先确定用什么数据结构。
看到翻转,二话不说就用splay。
第一个操作:在第posi
位后加入tot
个数字。我们就把这一段数字建出一个子splay。用类似线段树的建树方式解决掉,比一个一个加入的建树方式快,常数小。然后split出来中间的位置,暴力连接,pushup
即可。
第二个操作:在第posi
位后连续删除tot
个数字。我们spilt出来这段数字,然后暴力断开与主splay的链接。主splaypushup
一下,子splay就直接删除掉即可。
第三个操作:推平一段区间。我们使用lazy
标记记录一下即可。我们先表面改好,然后再给子节点加lazy
标记。听起来不难。
第四个操作:区间翻转。我们同样使用懒标记的思想。具体操作看“文艺平衡树”那道模板题。
第五个操作:求区间和。维护一下就是了。。。
第六个操作:求最大子序列。
这个问题最初是在线段树上的。
\(O(n)\)的算法能求一个固定数的最大子序列,但是一次修改就得跟一个\(O(n)\)是很慢的。
其实最大子序列有一个分治解法,是\(O(nlogn)\)的。这种方法可以用到线段树里面,使得一个修改是\(O(logn)\)的。
具体就是一个节点跟三个变量:mx
、lx
、rx
。
如何更新?放在pushup
里面更新。更新方法像在dp一样:
\(lx[l,r]=max(lx[l,mid],sum[l,mid]+lx[mid+1,r])\)
\(rx[l,r]=max(rx[mid+1,r],sum[mid+1,r]+rx[l,mid])rx[l,r]=max(rx[mid+1,r],sum[mid+1,r]+rx[l,mid])\)
\(mx[l,r]=max(mx[l,mid],mx[mid+1,r],lx[mid+1,r]+rx[l,mid+1])mx[l,r]=max(mx[l,mid],mx[mid+1,r],lx[mid+1,r]+rx[l,mid+1])\)
放在平衡树也简单,不就是多出了一个单独的节点\(mid\)吗?算进去就是了。
接下来麻烦的就来了!如何搞定这些懒标记的复杂关系?
显然,一个有推平标记的翻转没意义。所以可以直接忽略掉。所以先处理推平,后处理翻转。
翻转不只要交换左右儿子!还需要交换lx
和rx
!
翻转的写法我之前是直接改标记后就走人,所以他上面的根本就没改到。如果单纯只叫你维护翻转的话那样写是没问题的。
注意
-
mx[0]
、a[1]
和a[n+2]
都要设为-INF。因为有最大子序列。 -
注意pushup!!!
-
细心加耐心!!!
代码:
#include<cstdio>
#include<algorithm>
#include<stack>
const int maxn = 500005;
const int INF = 0x3f3f3f3f;
int a[maxn], id[maxn];
int fa[maxn], size[maxn], ch[maxn][2];
int val[maxn], sum[maxn];
int lx[maxn], mx[maxn], rx[maxn];
bool lazy[maxn], rev[maxn];
int root, tot;
int n, m;
std::stack<int> sta;
#define lson ch[x][0]
#define rson ch[x][1]
int read()
{
int ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar();
return s * ans;
}
int newnode()
{
if(!sta.empty())
{
int ret = sta.top(); sta.pop();
return ret;
}
return ++tot;
}
void clear_it(int x)
{
fa[x] = size[x] = ch[x][0] = ch[x][1] = val[x] = sum[x] = lx[x] = mx[x] = rx[x] = lazy[x] = rev[x] = 0;
}
int dir(int x)
{
return ch[fa[x]][1] == x;
}
void connect(int son, int f, int k)
{
fa[son] = f; ch[f][k] = son;
}
void pushup(int x)
{
size[x] = size[lson] + size[rson] + 1;
sum[x] = sum[lson] + sum[rson] + val[x];
lx[x] = std::max(lx[lson], sum[lson] + val[x] + lx[rson]);
rx[x] = std::max(rx[rson], sum[rson] + val[x] + rx[lson]);
mx[x] = std::max(std::max(mx[lson], mx[rson]), rx[lson] + val[x] + lx[rson]);
}
void rotate(int x)
{
int y = fa[x];
int z = fa[y];
int yk = dir(x);
int zk = dir(y);
int b = ch[x][yk ^ 1];
connect(b, y, yk);
connect(y, x, yk ^ 1);
connect(x, z, zk);
pushup(y);
pushup(x);
}
void splay(int x, int goal)
{
while(fa[x] != goal)
{
int y = fa[x];
int z = fa[y];
if(z != goal) dir(x) == dir(y) ? rotate(y) : rotate(x);
rotate(x);
}
if(goal == 0) root = x;
}
void pushdown(int x)
{
if(lazy[x])
{
lazy[x] = rev[x] = 0;
if(lson)
{
val[lson] = val[x]; sum[lson] = val[x] * size[lson];
if(val[x] >= 0) mx[lson] = lx[lson] = rx[lson] = sum[lson];
else mx[lson] = val[lson], lx[lson] = rx[lson] = 0;
lazy[lson] = 1;
}
if(rson)
{
val[rson] = val[x]; sum[rson] = val[x] * size[rson];
if(val[x] >= 0) mx[rson] = lx[rson] = rx[rson] = sum[rson];
else mx[rson] = val[rson], lx[rson] = rx[rson] = 0;
lazy[rson] = 1;
}
}
if(rev[x])
{
rev[x] = 0;
std::swap(ch[lson][0], ch[lson][1]);
std::swap(lx[lson], rx[lson]);
std::swap(ch[rson][0], ch[rson][1]);
std::swap(lx[rson], rx[rson]);
rev[lson] ^= 1; rev[rson] ^= 1;
}
}
int build(int f, int l, int r)
{
if(l > r) return 0;
if(l == r)
{
val[id[l]] = sum[id[l]] = a[l];
fa[id[l]] = id[f];
size[id[l]] = 1;
ch[id[l]][0] = ch[id[l]][1] = lazy[id[l]] = rev[id[l]] = 0;
mx[id[l]] = a[l];
lx[id[l]] = rx[id[l]] = std::max(a[l], 0);
return id[l];
}
int mid = (l + r) >> 1;
val[id[mid]] = a[mid];
fa[id[mid]] = id[f];
ch[id[mid]][0] = build(mid, l, mid - 1);
ch[id[mid]][1] = build(mid, mid + 1, r);
pushup(id[mid]);
return id[mid];
}
int kth(int k)
{
int x = root;
while(2333)
{
pushdown(x);
if(size[lson] + 1 < k)
{
k -= size[lson] + 1;
x = rson;
}
else if(size[lson] >= k) x = lson;
else return x;
}
}
int split(int l, int r)
{
l = kth(l), r = kth(r);
splay(l, 0), splay(r, l);
return ch[r][0];
}
void recycle(int x)
{
if(lson) recycle(lson);
if(rson) recycle(rson);
clear_it(x);
sta.push(x);
}
// functions
void Insert()
{
int posi = read(), tot = read();
for(int i = 1; i <= tot; i++) a[i] = read(), id[i] = newnode();
int del = build(0, 1, tot);
split(posi + 1, posi + 2);
connect(del, ch[root][1], 0);
pushup(ch[root][1]);// 10pt
pushup(root);
}
void Delete()
{
int posi = read(), tot = read();
int del = split(posi, posi + tot + 1);
ch[ch[root][1]][0] = 0; fa[del] = 0;// disconnect
pushup(ch[root][1]);
pushup(root);
recycle(del);
}
void Reverse()
{
int posi = read(), tot = read();
int del = split(posi, posi + tot + 1);
rev[del] ^= 1;
std::swap(ch[del][0], ch[del][1]);
std::swap(lx[del], rx[del]);
pushup(ch[root][1]);// 90pt
pushup(root);
}
void GetSum()
{
int posi = read(), tot = read();
int del = split(posi, posi + tot + 1);
printf("%d\n", sum[del]);
}
void MakeSame()
{
int posi = read(), tot = read(), c = read();
int del = split(posi, posi + tot + 1);
val[del] = c; sum[del] = c * size[del];
if(val[del] >= 0) lx[del] = rx[del] = mx[del] = sum[del];
else mx[del] = val[del], lx[del] = rx[del] = 0;
lazy[del] = 1;
pushup(ch[root][1]);
pushup(root);
}
void MaxSum()
{
printf("%d\n", mx[root]);
}
// debug
void print(int x)
{
if(lson) print(lson);
printf("%d ", val[x]);
if(rson) print(rson);
}
int main()
{
//freopen("testdata.in", "r", stdin);
//freopen("Test.out", "w", stdout);
n = read(), m = read();
mx[0] = a[1] = a[n+2] = -INF;
for(int i = 2; i <= n + 1; i++) a[i] = read();
for(int i = 1; i <= n + 2; i++) id[i] = ++tot;// give them id
root = build(0, 1, n + 2);
//print(root); printf("\n");
char opt[15];
while(m--)
{
scanf("%s", opt);
if(opt[0] == 'I') Insert();
else if(opt[0] == 'D') Delete();
else if(opt[0] == 'R') Reverse();
else if(opt[0] == 'G') GetSum();
else if(opt[2] == 'K') MakeSame();
else if(opt[2] == 'X') MaxSum();
//print(root); printf("\n");
}
return 0;
}