一道伸展樹維護數列的很悲傷的題目,共要維護兩個標記和兩個數列資訊,為了維護max-sum還要維護從左端開始的數列的最大和及到右端結束的數列的最大和。
按照伸展樹的套路,給數列左右兩邊加上不存在的邊界節點,給每個子樹的空兒子指向哨兵節點。
題目說的子數列其實要求至少包含乙個元素,這就要很噁心的維護方法。
(其實讓max_sum可以不含元素也能過90%)
每個節點定義max_sum:該節點的最大數列和(至少包含乙個元素)
max_lsum:該節點的從左端開始的最大數列和(可以不包含元素)
max_rsum:該節點的到右端結束的最大數列和(可以不包含元素)
按照分冶法,max_sum=max。
如果它和它的左右兒子都是普通節點,這個轉移保證至少有乙個元素。
如果它是普通節點或邊界節點,它的左或右兒子是哨兵節點,則左兒子max_sum或右兒子max_sum是不可取的。故令哨兵節點的max_sum=-inf。
如果它是邊界節點,它必定至多有乙個兒子,令它的max_sum等於它的唯一兒子的max_sum,max_lsum與max_rsum同理。
每個節點定義兩個標記replaced和reversed。
replaced:這個節點及它的所有後代都應該修改為乙個特定的值,但實際上只有這個節點的值已經修改。
reversed:這個節點及它的所有後代都應該交換左右子樹(max_lsum和max_rsum也應該跟著交換),但實際上只有這個節點的左右子樹已經交換。
可見這兩個標記是互斥的,且replaced標記的優先順序顯然大於reversed標記。
打標記的時候注意維護每個結點的標記至多有乙個就可以了。
350行的不壓行**,6.33kb,調了近8小時交了差不多二十遍才ac:
#include #include#include
#include
using
namespace
std;
void getstr(string &s)
dos += (char
)c;
while (isalpha(c = getchar()) || c == '-'
);}void getint(int &x)
dox = x * 10 + c - '0'
;
while (isdigit(c =getchar()));
if(flag)
x = -x;
}namespace
splay
;struct
node;
node *nil = 0, *l_edge, *r_edge;
struct
node
}int cmp(int
k)
void
reverse()
}void replace(int
v)
}void
push_down()
else
if(reversed)
}void
pull_up()
else
if (this == l_edge) //
注意特判左右邊界節點
else}}
void
remove()
}} *root;
void
init()
void rotate(node *&t, int
d)void splay(node *&t, int
k)
else
}else
rotate(t, d ^ 1
); }
}void join(node *&t1, node *&t2)
node *split(node *&t, int
k) splay(t, k);
node *subtree = t->ch[r];
t->ch[r] =nil;
t->pull_up();
return
subtree;
}node *build_tree(int *p, int
n)
return
fa;}
node *select(int p, int
tot)
}int
n, m;
int num[500005
];int
main()
else
//max_sum
cout << root->max_sum
; }
}return0;
}
noi2005維護數列
請寫乙個程式,要求維護乙個數列,支援以下 6 種操作 請注意,格式欄 中的下劃線 表示實際輸入檔案中的空格 操作編號 輸入檔案中的格式 說明1.插入 insert posi tot c1 c2 c tot 在當前數列的第 posi 個數字後插入 tot 個數字 c1,c2,c tot 若在數列首插 ...
NOI2005 維護數列
陳年老題。我就 碼了4k多。主要就是用splay,然後處理區間上的東西 區間反轉就和模板一樣,但是要記得反轉leftmax和rightmax 區間賦值就把那個區間提取出來,然後給子樹根打個same標記,表示下面的全一樣。區間求最大子段和就和線段樹的套路一樣。區間插入就先弄好一顆平衡樹,然後把原平衡樹...
NOI2005 維護數列
傳送門 我還是沒有逃過在這道題上debug好久的命運 我是使用 fhq treap 來做的這道題。寫的時候寫的挺爽的 調的時候真難受。首先我們先來說說咋做吧。前5個操作對於 fhq treap 來說不在話下,只要多打兩個標記就可以了。但是如何求最大子段和?於是乎我們再打三個標記來維護它 霧 然後我們...