【原题见q里?br />本题是Splay Tree处理序列问题Q也是当线D|用)的一个典型例题?br />
Splay Tree之所以可以当U段树用Q是因ؓ它可以支持一个序列,然后?#8220;左端前趋伸展到根Q右端后l展到根的叛_l点Q取根的叛_l点的左子结?#8221;q种伸展ҎQ对一个序列中的一整段q行整体操作。由于要防止出现前趋或后l不存在的情况,需要在q个序列的两端加入两个边界结点,要求其g能媄响到l点各种记蝲信息的维护(多取0?#8734;?∞Q。这两个边界l点在树中永q存在,不会被删除?br />
Q?Q结点的引用Q?br />在当U段树用的Splay Tree中,真正的关键字是下标而不是|因此Q?#8220;序列中第i个结?#8221;实际上对应的?#8220;树中W?i+1)的l点”Q因为左边还有一个边界结点)Q这p明在对结点引用时需要找WK的操作。因此,下面?#8220;l点x”指的?#8220;树中W?x+1)的l点”?br />Q?Q标讎ͼ
在线D|中,如果对一个结Ҏ表示的线D|体进行了某种操作Q需要在q个l点上打上一个标讎ͼ在下一ơ再扑ֈq个l点Ӟ其标记就会下攑ֈ其两个子l点上。在Splay Tree中也可以引入标记。比如要对[2, 6]q一D进行整体操作,将l点1伸展到根的位|,结?伸展到根的右子树的位|,然后l点7的左子树pC[2, 6]q一D,对这子树的根结Ҏ上标记ƈ立即生效Q必L立即生效Q而不是等下一ơ引用再生效Q,也就是立x变该l点记录的一些信息的倹{如果下ơ再ơ引用到q个l点Q就要将其标C攑ֈ其两个子l点处;
需要注意的一ҎQ如果要伸展某个l点x到r的子l点的位|,必M证从x原来的位|到r的这个子l点Qx伸展后的位置Q上的所有结点上均没有标讎ͼ否则׃D标记混ؕ。因此,必须首先扑ֈq个l点xQ在此过E中不断下放标记?br />Q?Q自底向上维护的信息Q?br />标记可以看成一U自向下维护的信息。除了标C外,作ؓ“U段?#8221;Q往往q要l护一些自底向上维护的信息。比如在sequenceq题中,有lmaxQ左D连l最大和Q、rmaxQ右D连l最大和Q、midmaxQ全D连l最大和Q以及sumQ全D|dQ等信息要维护。对于这cM东其实也很好办,因ؓ子树大小Qsz域)是一U自底向上维护的信息Q因此对于这些信息只要按照维护sz域的办法l护卛_Q统一写在upd函数里)。唯一的不同点是打标记时它们的值可能要改变?br />Q?Q对q箋插入的结点徏树:
本题的插入不是一个一个插入,而是一下子插入一整段Q因此需要先它们徏成一|。一般徏树操作都是递归的,q里也一栗设目前要对A[l..r]建树QA为待插入序列Q,若l>r则退出,否则扑ֈ位于中间的元素mid = l + r >> 1Q将A[mid]作根Q再对A[l..mid-1]建左子树Q对A[mid+1..r]建右子树卛_。这样可以保证一开始徏的就是一^衡树Q减常数因子?br />Q?Q回收空_
Ҏ本题的数据范围提C,插入的结ҎL最多可能达?000000Q但在Q何时L中最多只?00002个结点(包括两个边界Q,此时Z节省I间Q可以采用@环队列回收空间的Ҏ。即Q一开始将所有的可用I间Q可用下标,本题?~500002Q存在@环队列Q里,同时讄头尾指针front和rearQ每ơ如果有新结Ҏ入,取出Q[front]q作为新l点的下标,如果有结点要删除Q本题是一ơ删除整子树,因此在删除后需要分别回收它们的I间Q,则从rear开始,每个删除的l点的下标放回到Q里。当Ӟq种Ҏ是要牺牲一定的旉的,因此在空间不是特别吃紧的情况下不要用?br />
?012q??6日更新?br />今天重写sequence的时候,U然发现加入的边界点可能会对lmax、rmax、midmax{的l护造成影响Q当序列中所有的值都是负数时Q若边界点的D?Q将使这3个g?Q所以,边界点的值应设ؓ-INFQ不会媄响到sumQ因为可以单独调出[l, r]的sumQ避开边界Q。这p明ƈ非所有这L题中都可以设|边界点Q比如HFTSC2011的那题就不行Q,如果边界点会对维护的信息造成影响Q就不能讄边界点,在各个操作中Q分4U情况判断。(代码已经修改Q?br />
下面上代码了Q?
#include <iostream>
#include <stdio.h>
using namespace std;
#define re(i, n) for (int i=0; i<n; i++)
#define re1(i, n) for (int i=1; i<=n; i++)
const int MAXN = 500002, NOSM = -2000, INF = ~0U >> 2;
struct node {
int v, c[2], p, sz, sum, lmax, rmax, midmax, sm;
bool rev, d;
} T[MAXN + 1];
int root, Q[MAXN + 1], front, rear, a[MAXN], len, res;
int max(int SS0, int SS1)
{
return SS0 >= SS1 ? SS0 : SS1;
}
int max(int SS0, int SS1, int SS2)
{
int M0 = SS0 >= SS1 ? SS0 : SS1; return M0 >= SS2 ? M0 : SS2;
}
void newnode(int n, int _v)
{
T[n].v = T[n].sum = T[n].lmax = T[n].rmax = T[n].midmax = _v; T[n].c[0] = T[n].c[1] = 0; T[n].sz = 1; T[n].sm = NOSM; T[n].rev = 0;
}
void sc(int _p, int _c, bool _d)
{
T[_p].c[_d] = _c; T[_c].p = _p; T[_c].d = _d;
}
void sm_opr(int x, int SM)
{
T[x].sum = T[x].sz * SM;
if (SM > 0) T[x].lmax = T[x].rmax = T[x].midmax = T[x].sum; else T[x].lmax = T[x].rmax = T[x].midmax = SM;
}
void rev_opr(int x)
{
int c0 = T[x].c[0], c1 = T[x].c[1]; sc(x, c0, 1); sc(x, c1, 0);
int tmp = T[x].lmax; T[x].lmax = T[x].rmax; T[x].rmax = tmp;
}
void dm(int x)
{
int SM0 = T[x].sm;
if (SM0 != NOSM) {
T[x].v = T[T[x].c[0]].sm = T[T[x].c[1]].sm = SM0; T[x].sm = NOSM;
sm_opr(T[x].c[0], SM0); sm_opr(T[x].c[1], SM0);
}
if (T[x].rev) {
T[T[x].c[0]].rev = !T[T[x].c[0]].rev; T[T[x].c[1]].rev = !T[T[x].c[1]].rev; T[x].rev = 0;
rev_opr(T[x].c[0]); rev_opr(T[x].c[1]);
}
}
void upd(int x)
{
int c0 = T[x].c[0], c1 = T[x].c[1];
T[x].sz = T[c0].sz + T[c1].sz + 1;
T[x].sum = T[c0].sum + T[c1].sum + T[x].v;
T[x].lmax = max(T[c0].lmax, T[c0].sum + T[x].v + max(T[c1].lmax, 0));
T[x].rmax = max(T[c1].rmax, max(T[c0].rmax, 0) + T[x].v + T[c1].sum);
T[x].midmax = max(T[c0].midmax, T[c1].midmax, max(T[c0].rmax, 0) + T[x].v + max(T[c1].lmax, 0));
}
void rot(int x)
{
int y = T[x].p; bool d = T[x].d;
if (y == root) {root = x; T[root].p = 0;} else sc(T[y].p, x, T[y].d);
sc(y, T[x].c[!d], d); sc(x, y, !d); upd(y);
}
void splay(int x, int r)
{
int p; while ((p = T[x].p) != r) if (T[p].p == r) rot(x); else if (T[x].d == T[p].d) {rot(p); rot(x);} else {rot(x); rot(x);} upd(x);
}
int Find_Kth(int K)
{
int i = root, S0;
while (i) {
dm(i); S0 = T[T[i].c[0]].sz + 1;
if (K == S0) break; else if (K < S0) i = T[i].c[0]; else {K -= S0; i = T[i].c[1];}
}
return i;
}
int mkt(int l, int r)
{
if (l > r) return 0;
int n0 = Q[front], mid = l + r >> 1; if (front == MAXN) front = 1; else front++;
newnode(n0, a[mid]); int l_r = mkt(l, mid - 1), r_r = mkt(mid + 1, r);
sc(n0, l_r, 0); sc(n0, r_r, 1); upd(n0); return n0;
}
void ins(int pos)
{
int P0 = Find_Kth(pos); splay(P0, 0); int P1 = Find_Kth(pos + 1); splay(P1, root); sc(P1, mkt(0, len - 1), 0); upd(P1); upd(P0);
}
void era(int x)
{
if (!x) return;
if (rear == MAXN) rear = 1; else rear++; Q[rear] = x;
era(T[x].c[0]); era(T[x].c[1]);
}
void del(int l, int r)
{
int P0 = Find_Kth(l - 1); splay(P0, 0); int P1 = Find_Kth(r + 1); splay(P1, root);
int root0 = T[P1].c[0]; sc(P1, 0, 0); upd(P1); upd(P0); era(root0);
}
void mksame(int l, int r, int x)
{
int P0 = Find_Kth(l - 1); splay(P0, 0); int P1 = Find_Kth(r + 1); splay(P1, root);
int n = T[P1].c[0]; T[n].sm = x; sm_opr(n, x); upd(P1); upd(P0);
}
void reve(int l, int r)
{
int P0 = Find_Kth(l - 1); splay(P0, 0); int P1 = Find_Kth(r + 1); splay(P1, root);
int n = T[P1].c[0]; T[n].rev = !T[n].rev; rev_opr(n); upd(P1); upd(P0);
}
int get_sum(int l, int r)
{
int P0 = Find_Kth(l - 1); splay(P0, 0); int P1 = Find_Kth(r + 1); splay(P1, root);
int n = T[P1].c[0]; return T[n].sum;
}
int max_sum()
{
return T[root].midmax;
}
void prepare()
{
T[0].sz = T[0].sum = T[0].lmax = T[0].rmax = T[0].midmax = 0;
front = 3; rear = MAXN; re1(i, MAXN) Q[i] = i;
newnode(1, -INF); newnode(2, -INF); sc(1, 2, 1); root = 1; T[root].p = 0;
}
int main()
{
freopen("sequence.in", "r", stdin);
freopen("sequence.out", "w", stdout);
prepare();
int m, l, r, x;
scanf("%d%d", &len, &m); char ch = getchar(), str[1000];
re(i, len) scanf("%d", &a[i]); ins(1);
re(i, m) {
scanf("%s", str);
if (!strcmp(str, "INSERT")) {scanf("%d%d", &l, &len); re(i, len) scanf("%d", &a[i]); ins(++l);}
if (!strcmp(str, "DELETE")) {scanf("%d%d", &l, &r); r += l++; del(l, r);}
if (!strcmp(str, "MAKE-SAME")) {scanf("%d%d%d", &l, &r, &x); r += l++; mksame(l, r, x);}
if (!strcmp(str, "REVERSE")) {scanf("%d%d", &l, &r); r += l++; reve(l, r);}
if (!strcmp(str, "GET-SUM")) {scanf("%d%d", &l, &r); r += l++; printf("%d\n", get_sum(l, r));}
if (!strcmp(str, "MAX-SUM")) printf("%d\n", max_sum());
ch = getchar();
}
fclose(stdin); fclose(stdout);
return 0;
}
最后把我的q个代码与BYVoid犇的本题代码进行测试比较,l果QBYVoid犇的代码见q里Q:
BYVoid犇的:

本沙茶的Q?br />
【相兌文?br />
]]>