怎么说呢,两夜鏖战,一上午奋斗,终于弄出来了。
最近很萎。无奈啊。今天上午强打精神搞完了,下午小小放松(我才不堕落!只是睡觉...)
保持这种干劲啊少年~
====================特别鸣谢============================
真心的感谢Roosephu大牛,一直指导我做,我很多东西都不懂,但他很耐心的教我...他也有他自己的事...但是这么努力的帮我...
真的非常感谢...
还有DRJ.....被您的代码坑了一下,不过还是感谢代码带给我的指导与启发。非常感谢。
====================闲话少说,以下正文====================
为啥说基础题?因为做完了就会splay的基本操作了。
给大家一道思考题,
sequence+求第k大元素怎么做?
....(好吧,邓大牛说是LCT)
好吧,这就不是基本操作了。所以您懂基础题是怎么来的了吧..
关于Sequence的题解网上很多,也有各种各样的写法。我就自己的感受谈一谈吧。
首先是MAX-SUM,作为蒟蒻,理解了很久...【雾】
如下图:
然后,序列最前端和最后端设立哨兵head, tail(防止插入到NULL上去)
优化:
在 rotate 过程中不需要下放标记,不 update 当前节点。max,swap 之类的自己Define。
(详见http://blog.csdn.net/jerrydung/article/details/7952460)
但是他说的还不够。还有几个很重要的。
1.内存池:
struct node
{
node *f, *c[2];
int v, maxl, maxr, maxm, s, sum;
bool rev, mrk;
}vess[maxn];
typedef node *NODE;
NODE pool[maxn];
for (int i = 0; i <= maxn; i++) pool[i] = &vess[i];
pool实际上是一个栈,删除时将要删除的子树根节点进栈。
每次从栈中取出一个元素,如果发现其子节点不是null,就把子节点进栈。
为什么要这样呢?因为空间只有32MB,所以必须写动态(当然,32MB只是考场上...不过嘛,BZOJ上也是)
c++的new和delete是很慢的,所以内存池可以很大程度上提高效率。
优化2:
插入序列时,把序列弄成一颗近似完全二叉树再插进去。
NODE build(int l, int r)
{
int m = (l + r) >> 1, d;
NODE lc = null, rc = null;
if (m > l)
lc = build(l, m - 1);
scanf("%d", &d);
NODE t = newnode(null, d, 0);
if (m < r)
rc = build(m + 1, r);
setc(t, 0, lc);
setc(t, 1, rc);
return update(t);
}
当你要插入一段长为tot的区间时,调用build(1, tot)即可。
惊人的是,这个优化使程序跑最大数据时快了0.4s,强烈推荐。
然后,一些细节:
1.我曾经把make-same的标记写成了(int same),有标记时same改为需要变成的值
void putsame(NODE x, int k)
{
if (x == null) return;
x -> v = k;
x -> same = k; //就是这一句
x -> sum = x -> s * k;
x -> maxl = x -> maxr = x -> maxm = max(x -> sum, k);
x -> rev = 0;
}
然后pushdown判断same是否为0
但实际上,存在把所有数字改为0的情况,然后就萎了..
2.在程序中注意null的判断,在调试时看null内元素的值有没有变为意料外的值是检查的办法之一。
3.head、tail、null的初值注意一下。
4.在新建节点时,其父节点、爷爷节点、太爷爷节点(雾)的size是不用更新的。反正插完要rotate,rotate会update,所以就无所谓了。
5.关于pushdown:roosephu说了一句话:在pushdown之后,保证该节点的值是正确的。
很有用的一句话。可以帮助理解。我刚开始想了很久..
这是AC的图。
BZOJ
本地的
下面是代码。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define max(i, j) ({int _ = (i), __ = (j); _ > __ ? _ : __;})
#define maxn 500005
#define oo 0x3F3F3F3F
#define swap(t, i, j) ({t _ = (i); (i) = (j); (j) = _;})
#define setc(F,d,C) (((F) -> c[d] = (C)) -> f = (F))
using namespace std;
int n, tot = maxn, m;
struct node
{
node *f, *c[2];
int v, maxl, maxr, maxm, s, sum;
bool rev, mrk;
}vess[maxn];
typedef node *NODE;
NODE root, null, pool[maxn], head, tail;
NODE newnode(NODE fa, int val, bool k)
{
NODE x = pool[--tot];
if (x -> c[0] != null) pool[tot++] = x -> c[0], x -> c[0] = null;
if (x -> c[1] != null) pool[tot++] = x -> c[1], x -> c[1] = null;
x -> f = fa; x -> s = 1; if (fa != null) fa -> c[k] = x;
x -> v = x -> maxl = x -> maxr = x -> maxm = x -> sum = val;
x -> rev = x -> mrk = 0;
return x;
}
NODE l, r;
NODE update(NODE x)
{
if (x == null) return null;
l = x -> c[0], r = x -> c[1];
x -> s = l -> s + r -> s + 1;
x -> sum = l -> sum + r -> sum + x -> v;
x -> maxl = max(l -> maxl, l -> sum + x -> v + max(0, r -> maxl));
x -> maxr = max(r -> maxr, r -> sum + x -> v + max(0, l -> maxr));
x -> maxm = max(max(l -> maxm, r -> maxm), max(l -> maxr, 0) + x -> v + max(r -> maxl, 0));
return x;
}
void putsame(NODE x, int k)
{
if (x == null) return;
x -> v = k;
x -> mrk = 1;
x -> sum = x -> s * k;
x -> maxl = x -> maxr = x -> maxm = max(x -> sum, k);
x -> rev = 0;
}
void putrev (NODE x)
{
x -> rev ^= 1;
swap(int, x -> maxl, x -> maxr);
swap(NODE, x -> c[0], x -> c[1]);
}
NODE pushdown(NODE x)
{
if (x == null) return null;
if (x -> mrk) putsame(x -> c[0], x -> v), putsame(x -> c[1], x -> v), x -> mrk = 0;
if (x -> rev) putrev(x -> c[0]), putrev(x -> c[1]), x -> rev = 0;
return x;
}
void rotate(NODE x)
{
NODE y = x -> f, z = y -> f; int k = (x == y->c[1]);
x -> f = z; if (z != null) z -> c[y == z -> c[1]] = x;
if (x -> c[!k] != null) setc(y, k, x -> c[!k]); else y -> c[k] = null;
setc(x, !k, update(y));
}
NODE splay(NODE to, NODE x)
{
pushdown(x);
for (pushdown(x); x -> f != to; rotate(x))
if (x -> f -> f != to)
rotate((x -> f -> f -> c[1] == x -> f) ^ (x->f->c[1] == x) ? x : x -> f);
if (to == null) root = x;
return update(x);
}
NODE find(int k, NODE to)
{
NODE t = to;
int w;
while(k != (w = pushdown(t) -> c[0] -> s))
if (k > w) k -= w + 1, t = t -> c[1];
else t = t -> c[0];
pushdown(t);
return splay(to -> f, t);
}
void prepare()
{
null = new node();
*null = (node){null, {null, null}, -oo, -oo, -oo, -oo, 0, 0, 0, 0};
for (int i = 0; i <= maxn; i++) pool[i] = &vess[i], pool[i] -> c[0] = pool[i] -> c[1] = null;
}
NODE build(int l, int r)
{
int m = (l + r) >> 1, d;
NODE lc = null, rc = null;
if (m > l)
lc = build(l, m - 1);
scanf("%d", &d);
NODE t = newnode(null, d, 0);
if (m < r)
rc = build(m + 1, r);
setc(t, 0, lc);
setc(t, 1, rc);
return update(t);
}
void init()
{
freopen("sequence.in", "r", stdin);
freopen("sequence.out", "w", stdout);
}
int main()
{
prepare();
init();
scanf("%d%d", &n, &m);
root = build(1, n);
head = newnode(null, 0, 0);
head -> maxl = head -> maxr = head -> maxm = head -> v = -oo;
tail = newnode(head, 0, 1);
tail -> maxl = tail -> maxr = tail -> maxm = tail -> v = -oo;
setc(tail, 0, root);
update(tail); update(head);
root = head;
char s[200], c;
int pos, total, ll;
while (m--)
{
scanf("%s", s);
c = s[2];
if (c == 'X')
{
printf("%d\n", root -> maxm); continue;
}
scanf("%d%d", &pos, &total);
if (c == 'S')
{
find(pos, root);
find(0, root -> c[1]);
setc(root -> c[1], 0, build(1, total));
}
else
{
find(pos - 1, root);
find(total, root -> c[1]);
if (c == 'L')
{
pool[tot++] = root -> c[1] -> c[0];
root -> c[1] -> c[0] = null;
}
else if (c == 'T')
printf("%d\n", root -> c[1] -> c[0] -> sum);
else if (c == 'V')
putrev(root -> c[1] -> c[0]);
else
{
scanf("%d", &ll);
putsame(root -> c[1] -> c[0], ll);
}
}
update(root -> c[1]); update(root);
}
return 0;
}