維護一個初始為空的序列,支持三種操作:
i,插入位置 pos;同時插入 -i 到第 k+1 個負數之前(k 為 +i 前的正數個數),保持正負數相對順序。i 和 -i。i 和 -i 之間元素和。m ≤ 200000 操作。
val:值(正/負)sum:子樹值和z:子樹正數個數f:子樹負數個數num = seg.query_min() 獲取最小可用正整數。+num 到位置 pos+1(Splay 以 1-based 索引,含哨兵節點)。記錄節點指針 pos1[num]。z[root] 即 +num 前的正數個數 k。f[root] ≤ k,則 -num 插到序列末尾(size-1 位置)。kth(root, k) 找第 k+1 個負數位置,插在其前。記錄 pos2[num]。num 為已用(置 INF)。pos1[num] 到根,刪除該節點(雙旋刪除哨兵間節點)。pos2[num]。num 為可用(置 num)。pos1[num] 到根,pos2[num] 到根的右子樹。keyTree->sum(中間子樹)。O(log n)。O(log m)。O(m log m),通過 m=200000。// Splay 節點
int ch[MAXN][2], pre[MAXN], siz[MAXN], val[MAXN];
long long sum[MAXN];
int z[MAXN], f[MAXN]; // 正/負計數
// Segment Tree
int seg[MAXN<<2];
void build(int o, int l, int r) { ... }
void update(int o, int l, int r, int pos, int val) { ... }
int query_min() { return seg[1]; } // 根存最小可用數
// Splay 基礎操作:rotate, splay, rotateTo(k, goal)
// kth(x, n): 找第 n 個負數位置
// insert(pos, v): 旋轉到位置插入
// remove(num): 旋轉到節點刪除
完整代碼見原文,包含調試用 Treaval 遍歷輸出。
本題綜合考察 Splay Tree 維護序列結構 + Segment Tree 維護最小可用數。關鍵難點:
kth 找負數排名)。是數據結構綜合應用的優秀練習題。