給定 N 個整數序列,支援兩種操作(Q ≤ 100,000):
C a b c:區間 [a, b] 每個數加上 c。Q a b:查詢區間 [a, b] 的和。數值範圍大,需 64 位整數。本文使用 Splay 树(伸展树)維護序列,利用中序遍歷有序性實現區間操作。
const int MAXN = 100000 + 100;
LL add[MAXN], sum[MAXN]; // 懶標記、子樹和
int ch[MAXN][2], siz[MAXN]; // 左右子、子樹大小
int key[MAXN], pre[MAXN]; // 節點值、父節點
int A[MAXN]; // 初始值陣列
int root, tot; // 根節點、節點總數
push_down:將當前節點的 add 標記傳遞給左右子,更新子節點的 key、sum、add。push_up:根據左右子更新 siz、sum。Rotate:支援左/右旋,旋轉前先 push_down 父子節點,旋轉後先 push_up 子再父。Splay(x, goal):將節點 x 伸展到 goal 之下(goal=0 為根),使用 Zig-Zig / Zig-Zag 雙旋優化。Get_kth:利用左子樹大小定位序列中第 k 個節點。對於區間 [l, r]:
Splay(Get_kth(root, l), 0); // 將 l 伸展到根
Splay(Get_kth(root, r+2), root); // 將 r+2 伸展到根的右子
// 此時目標區間正是 root->right->left 子樹
int target = ch[ch[root][1]][0];
sum[target]。target 調用 Modify(target, c),再 push_up 祖先節點。// 完整代碼見原文,包含:newnode, built, Init, Rotate, Splay, Get_kth, Modify, push_up, push_down, main
// 主迴圈讀取指令,根據 'Q'/'C' 分派處理,輸出查詢結果。