[BZOJ 1500] [NOI2005] 维修数列
題目鏈接:BZOJ - 1500
?
題目分析
我要先說(shuō)一下,這道題我寫(xiě)了一晚上,然后Debug了一整個(gè)白天..........再一次被自己的蒟蒻程度震驚= =
這道題是傳說(shuō)中的Splay維護(hù)數(shù)列的Boss題目。
前面的幾個(gè)操作和詢問(wèn)看起來(lái)比較正常,就是最后一個(gè)維護(hù)最大區(qū)間和比較復(fù)雜。
其實(shí)這個(gè)也并不是十分復(fù)雜,只是要多維護(hù)一點(diǎn)東西,事實(shí)證明,我代碼里的錯(cuò)誤都不是與這個(gè)詢問(wèn)有關(guān)的。
維護(hù)每個(gè)節(jié)點(diǎn)的 Lmx[x] ,即這個(gè)節(jié)點(diǎn)的子樹(shù)代表的區(qū)間的從左端開(kāi)始的最大權(quán)值和。Rmx[x],同理。Mx[x],這個(gè)區(qū)間的最大權(quán)值和。
然而我的最大權(quán)值和都是可以為空的,也就是說(shuō)如果只能取負(fù)數(shù)我就什么都不取,就是0。
題目規(guī)定的最大權(quán)值區(qū)間是不能為空的,所以我多維護(hù)了一個(gè) Max[x],詢問(wèn)的時(shí)候判斷如果 Max[x] < 0 ,就輸出 Max[x],否則輸出我維護(hù)的 Mx[x]。
............................然后就是我Debug了一天的東西.........................
經(jīng)過(guò)一天悲劇的探索與嘗試,我發(fā)現(xiàn)我的錯(cuò)誤是出現(xiàn)在了Reverse操作有關(guān)的東西。
PushDown寫(xiě)得有非常嚴(yán)重的錯(cuò)誤,下面來(lái)梳理一下正確的寫(xiě)法,以后要固定一下寫(xiě)法,不能一個(gè)代碼一個(gè)寫(xiě)法...
首先,翻轉(zhuǎn)一個(gè)區(qū)間的時(shí)候,假如這個(gè)區(qū)間子樹(shù)的根節(jié)點(diǎn)是 x,就Reverse(x)。
之后,PushDown(x) 的時(shí)候,判斷 Rev[x] 是否為 1,如果是1,就Reverse(Son[x][0]); Reverse(Son[x][1]);
注意,交換左右兒子的操作在Reverse(x)里完成。Rev[x]為1表示的是x的兩個(gè)兒子還應(yīng)被 Reverse,但是x的兩個(gè)兒子的順序已經(jīng)是對(duì)的。是x的孫子的順序需要被交換。
代碼:
void Reverse(int x) {Rev[x] ^= 1;swap(Son[x][0], Son[x][1]); } void PushDown(int x) {if (Rev[x] == 0) return;if (Son[x][0]) Reverse(Son[x][0]); if (Son[x][1]) Reverse(Son[x][1]); Rev[x] = 0; }
代碼
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm>using namespace std;const int MaxN = 1000000 + 5, INF = 999999999;inline void Read(int &Num) {char c = getchar();bool Neg = false;while (c < '0' || c > '9'){if (c == '-') Neg = true;c = getchar();}Num = c - '0'; c = getchar();while (c >= '0' && c <= '9'){Num = Num * 10 + c - '0';c = getchar();}if (Neg) Num = -Num; }int n, m, Root, Index, Tot1, Tot2, Len; int V[MaxN], A[MaxN], Father[MaxN], Son[MaxN][2], Sum[MaxN], Rev[MaxN], Stack[MaxN]; int Max[MaxN], Size[MaxN], Lmx[MaxN], Rmx[MaxN], Mx[MaxN], D[MaxN];bool Rep[MaxN];char Str[15];inline int gmax(int a, int b) {return a > b ? a : b;} inline int gmin(int a, int b) {return a < b ? a : b;}inline void Update(int x) {Size[x] = Size[Son[x][0]] + Size[Son[x][1]] + 1;Sum[x] = Sum[Son[x][0]] + Sum[Son[x][1]] + A[x];Max[x] = gmax(A[x], gmax(Max[Son[x][0]], Max[Son[x][1]]));Lmx[x] = gmax(Lmx[Son[x][0]], Sum[Son[x][0]] + A[x] + Lmx[Son[x][1]]);Rmx[x] = gmax(Rmx[Son[x][1]], Sum[Son[x][1]] + A[x] + Rmx[Son[x][0]]);Mx[x] = gmax(Rmx[Son[x][0]] + A[x] + Lmx[Son[x][1]], gmax(Rmx[x], Lmx[x]));Mx[x] = gmax(Mx[x], gmax(Mx[Son[x][0]], Mx[Son[x][1]])); }inline void Replace(int x, int Num) {Rep[x] = true;D[x] = Num;A[x] = Num;Sum[x] = Num * Size[x];Max[x] = Num; Lmx[x] = Rmx[x] = Mx[x] = gmax(0, Sum[x]); }inline void Reverse(int x) {Rev[x] ^= 1;swap(Son[x][0], Son[x][1]);swap(Lmx[x], Rmx[x]); }inline void PushDown(int x) {if (Rep[x]){if (Son[x][0]) Replace(Son[x][0], D[x]);if (Son[x][1]) Replace(Son[x][1], D[x]);Rep[x] = false;}if (Rev[x]) {if (Son[x][0]) Reverse(Son[x][0]);if (Son[x][1]) Reverse(Son[x][1]);Rev[x] = 0;} }int NewNode(int a) {int x;if (Tot2 > 0) x = Stack[Tot2--];else x = ++Tot1;Size[x] = 1;Son[x][0] = Son[x][1] = 0;Father[x] = 0;A[x] = Sum[x] = Max[x] = a;Lmx[x] = Rmx[x] = Mx[x] = gmax(a, 0);Rev[x] = 0; Rep[x] = false;return x; }int Build(int s, int t) {int x, m = (s + t) >> 1;x = NewNode(V[m]);if (s < m) {Son[x][0] = Build(s, m - 1);Father[Son[x][0]] = x;}if (t > m) {Son[x][1] = Build(m + 1, t);Father[Son[x][1]] = x;}Update(x);return x; }void Rotate(int x, int f) {int y = Father[x];if (y == 0) return;Son[y][f ^ 1] = Son[x][f];if (Son[x][f]) Father[Son[x][f]] = y;Father[x] = Father[y];if (Father[y]) {if (y == Son[Father[y]][0]) Son[Father[y]][0] = x;else Son[Father[y]][1] = x;}Son[x][f] = y;Father[y] = x;Update(y);Update(x); }void Splay(int x, int d) {if (x == d) return;int y;while (Father[x] != d) {y = Father[x];if (Father[y] == d) {if (x == Son[y][0]) Rotate(x, 1);else Rotate(x, 0);break; }if (y == Son[Father[y]][0]) {if (x == Son[y][0]){Rotate(y, 1);Rotate(x, 1);}else{Rotate(x, 0);Rotate(x, 1);}}else{if (x == Son[y][1]){Rotate(y, 0);Rotate(x, 0);}else{Rotate(x, 1);Rotate(x, 0);}}}if (Father[x] == 0) Root = x; }int Find(int Num) {int x = Root, k = Num;PushDown(x);while (Size[Son[x][0]] + 1 != k){if (Size[Son[x][0]] + 1 > k){x = Son[x][0];}else{k -= Size[Son[x][0]] + 1;x = Son[x][1];}PushDown(x);}return x; }void Delete(int x) {if (x == 0) return;if (Son[x][0]) Delete(Son[x][0]);if (Son[x][1]) Delete(Son[x][1]);Stack[++Tot2] = x; }int main() {scanf("%d%d", &n, &m);Tot1 = Tot2 = 0;Len = n;for (int i = 1; i <= n; ++i) Read(V[i]);Max[0] = -INF;int Temp;Root = Build(1, n);Splay(Find(1), 0);Temp = NewNode(-INF);Son[Root][0] = Temp;Father[Temp] = Root;Update(Root);Splay(Find(n + 1), 0);Temp = NewNode(-INF);Son[Root][1] = Temp;Father[Temp] = Root;Update(Root);int Pos, Tot, New, Num, x, y;for (int i = 1; i <= m; ++i) {scanf("%s", Str);if (strcmp(Str, "INSERT") == 0) {Read(Pos); Read(Tot);Len += Tot;for (int j = 1; j <= Tot; ++j) scanf("%d", &V[j]);New = Build(1, Tot);x = Find(Pos + 1);y = Find(Pos + 2);Splay(x, 0);Splay(y, x);Son[y][0] = New;Father[New] = y;Update(y);Update(x);}else if (strcmp(Str, "DELETE") == 0){Read(Pos); Read(Tot);Len -= Tot;x = Find(Pos);y = Find(Pos + Tot + 1);Splay(x, 0);Splay(y, x);Delete(Son[y][0]);Son[y][0] = 0;Update(y);Update(x);}else if (strcmp(Str, "MAKE-SAME") == 0){Read(Pos); Read(Tot); Read(Num);x = Find(Pos);y = Find(Pos + Tot + 1);Splay(x, 0);Splay(y, x);Replace(Son[y][0], Num);Update(y);Update(x);}else if (strcmp(Str, "REVERSE") == 0){Read(Pos); Read(Tot);x = Find(Pos);y = Find(Pos + Tot + 1);Splay(x, 0);Splay(y, x);Reverse(Son[y][0]);Update(y);Update(x);}else if (strcmp(Str, "GET-SUM") == 0){Read(Pos); Read(Tot);x = Find(Pos);y = Find(Pos + Tot + 1);Splay(x, 0);Splay(y, x);printf("%d\n", Sum[Son[y][0]]);}else if (strcmp(Str, "MAX-SUM") == 0){x = Find(1);y = Find(Len + 2);Splay(x, 0);Splay(y, x);if (Max[Son[y][0]] <= 0) printf("%d\n", Max[Son[y][0]]);else printf("%d\n", Mx[Son[y][0]]);}}return 0; }
轉(zhuǎn)載于:https://www.cnblogs.com/JoeFan/p/4336035.html
總結(jié)
以上是生活随笔為你收集整理的[BZOJ 1500] [NOI2005] 维修数列的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
                            
                        - 上一篇: 怎么下载启动盘到u盘 制作U盘启动盘的方
 - 下一篇: 笔记本win10怎么设置ip win10