这道题能用辣鸡度搜出来的treap做法只有两三篇吧,并且没有详解。。。
先看数据范围,本蒟蒻感觉nlogn过不了啊。。。 [主要是我是大常数选手]
其实可以勉强过,
跪烂了那些只跑1s多的神犇%%%
首先,四百万次的插入,如果你每次都申请一个新的空间,肯定是要MLE的。
我们注意到数列中最多只有五十万个元素,也就是说我们最多同时用到五十万个空间。那么可以这样处理:维护一个栈,删除时将要删除的元素加到栈里,每次申请新的节点时先看栈里还有没有元素,如果有,那么将栈顶出栈,用于新申请的元素,否则新申请空间,,
Treap *newnode (int xxx) { if (top) return new (stk[top--]) Treap (xxx, Null); return new (pool++) Treap (xxx, Null); }
求区间最大值的话,对于一个节点多维护如下信息,以这个节点为根的子树代表的序列,最右边一段连续数值最大和是多少,最左边一段连续数值的最大和是多少,这段区间最大的一段连续子序列和是多少。(分别记为rmax, lmax, mmax)当前节点的值记为data, 当前节点所代表的子树的元素和为sum,size代表该子树元素个数。
rmax可以这样转移 : 它等于 Max (右儿子的rmax,data + 右儿子的sum + Max (左儿子的rmax,0))。
如图,DE代表当前节点的那个元素,BC为当前节点代表的子树,BD代表当前节点的左儿子所代表的子树,EC代表当前节点的右儿子所代表的子树,如果BC这段区间的rmax的那段区间在EC中,那么它就是CE的rmax,如果不在EC中,即左端点在E的左边,那么它就等于BE这段区间的rmax加上EC这段区间的和,BE这段区间的rmax怎么求呢?首先DE必须要选(因为左端点在e左边),那么我们就可以看BD的rmax了。如果BD的rmax < 0 ,那么选了他会让BC的rmax变小,不如不选。所以可以得出上面的式子。
选右儿子同理。那么当前节点的mmax = Max (当前节点的lmax,当前节点的rmax,左儿子的mmax,右儿子的mmax,Max(0,左儿子的rmax)+Max(0,右儿子的lmax)+data)
至于为什么这样,就留给你们自己思考啦。
void update () { if (l != Null) l -> pushdown (); if (r != Null) r -> pushdown (); size = l -> size + r -> size + 1; sum = l -> sum + r -> sum + data; lmax = data + std :: max (r -> lmax, 0); rmax = data + std :: max (l -> rmax, 0); if (l != Null) lmax = std :: max (l -> lmax, l -> sum + lmax); if (r != Null) rmax = std :: max (r -> rmax, r -> sum + rmax); mmax = std :: max (std :: max (l -> mmax, r -> mmax), std :: max (std :: max(lmax, rmax), std :: max (l -> rmax, 0) + std :: max (r -> lmax, 0) + data)); }
那么怎样下放标记呢,对于翻转的标记,把左右儿子交换,将lmax , rmax交换即可。对于覆盖的标记,就是把data改成标记的值,sum改成data*size。如果data是大于零的,那么这段区间的最大值就应该是sum。(即lmax = rmax = mmax = sum) 否则,由于至少要选一个元素,那么最大值就为data (即lmax = rmax = mmax = data)。
void pushdown () { if (l1) { l -> l1 ^= 1; r -> l1 ^= 1; l1 ^= 1; std :: swap (l, r); std :: swap (lmax, rmax); } if (l21) { l -> l21 = r -> l21 = true; l -> l22 = r -> l22 = l22; l21 = false; data = l22; sum = data * size; lmax = rmax = mmax = l22 > 0 ? sum : data; } }
最后上代码,反正细节挺多的。。。 我语文不好,感觉对不住观众朋友QAQ
#include<cstdio> #include<cstring> #include<cstdlib> #include<string> #include<iostream> #include<algorithm> #include<cctype> #include<cmath> const int N = 5e5 + 9; int top, n, m; struct Treap *Null; struct Treap { int data, sum, size, hr, lmax, rmax, mmax; bool l1, l21; int l22; Treap *l, *r; Treap () {} Treap (int data, Treap *fl) : data(data), sum(data), size(1), hr(rand()), lmax(data), rmax(data), mmax(data), l1(0), l21(0), l(fl), r(fl) {} void update () { if (l != Null) l -> pushdown (); if (r != Null) r -> pushdown (); size = l -> size + r -> size + 1; sum = l -> sum + r -> sum + data; lmax = data + std :: max (r -> lmax, 0); rmax = data + std :: max (l -> rmax, 0); if (l != Null) lmax = std :: max (l -> lmax, l -> sum + lmax); if (r != Null) rmax = std :: max (r -> rmax, r -> sum + rmax); mmax = std :: max (std :: max (l -> mmax, r -> mmax), std :: max (std :: max(lmax, rmax), std :: max (l -> rmax, 0) + std :: max (r -> lmax, 0) + data)); } void pushdown () { if (l1) { l -> l1 ^= 1; r -> l1 ^= 1; l1 ^= 1; std :: swap (l, r); std :: swap (lmax, rmax); } if (l21) { l -> l21 = r -> l21 = true; l -> l22 = r -> l22 = l22; l21 = false; data = l22; sum = data * size; lmax = rmax = mmax = l22 > 0 ? sum : data; } } }*root, meme[N], *pool = meme, *stk[N]; void rec (Treap *x) { if (x == Null) return ; rec (x -> l); rec (x -> r); stk[++top] = x; } Treap *newnode (int xxx) { if (top) return new (stk[top--]) Treap (xxx, Null); return new (pool++) Treap (xxx, Null); } Treap *Merge (Treap *A, Treap *B) { if (A == Null) return B; if (B == Null) return A; if (A -> hr > B -> hr) { B -> pushdown (); B -> l = Merge (A, B -> l); B -> update (); return B; } else { A -> pushdown (); A -> r = Merge (A -> r, B); A -> update (); return A; } } using std :: pair; typedef pair <Treap *, Treap *> Droot; Droot Split (Treap *x, int k) { if (x == Null) return Droot (Null, Null); Droot y; x -> pushdown (); if (x -> l -> size >= k) { y = Split (x -> l, k); x -> l = y . second; x -> update (); y . second = x; } else { y = Split (x -> r, k - x -> l -> size - 1); x -> r = y . first; x -> update (); y . first = x; } return y; } int num; bool fl; char a; int getin () { num = fl = 0; for (a = getchar (); a < '0' || a > '9'; a = getchar()) if (a == '-') fl = true; for (; a >= '0' && a <= '9'; a = getchar()) num = (num << 3) + (num << 1) + a - '0'; if (fl) num = -num; return num; } Treap *Build () { Treap *x, *last; stk[1] = Null; for (int i = 1; i <= n; ++i) { x = new (pool++) Treap (getin (), Null); last = Null; while (top && stk[top] -> hr > x -> hr) { stk[top] -> update (); last = stk[top--]; } if (top) stk[top] -> r = x; x -> l = last; stk[++top] = x; } while (top) stk[top--] -> update (); return stk[1]; } Droot clc2, clc1; char opt[20]; Treap *clc3; int main () { Null = new Treap (-0x7fffffff, NULL); Null -> size = Null -> sum = 0; n = getin (); m = getin (); root = Build (); while (m--) { scanf ("%s", opt); if (opt[2] == 'X') printf ("%d ", root -> mmax); else if (opt[2] == 'S') { clc1 = Split (root, getin()); clc3 = Null; for (int i = getin(); i; --i) clc3 = Merge (clc3, newnode (getin())); root = Merge (clc1 . first, Merge (clc3, clc1 . second)); } else { clc1 = Split (root, getin() - 1); clc2 = Split (clc1 . second, getin()); if (opt[2] == 'K') clc2 . first -> l21 = true, clc2 . first -> l22 = getin (); if (opt[2] == 'V') clc2 . first -> l1 = true; if (opt[2] == 'T') printf ("%d ", clc2 . first -> sum); if (opt[2] == 'L') rec (clc2 . first), root = Merge (clc1 . first, clc2 . second); else root = Merge (clc1 . first, Merge (clc2 . first, clc2 . second)); } } return 0; }