實現一個支持 7 種操作的文本編輯器:
數據範圍:操作數 ≤ 50,000,插入總字符數 ≤ 2M,Get 操作 ≤ 20,000。要求高效支持區間操作。
將文本序列映射為 Splay 树的中序遍歷序列,每個節點存儲一個字符。通過 雙哨兵節點(頭尾虛擬節點)統一邊界處理。核心操作統一為:
key = c[c[rt][1]][0])key 所在子樹施加操作(打標記、修改指針等)// 節點結構
struct Node {
int ch[2], fa, size;
char val;
bool rev; // 翻轉標記
} t[MAXN];
// 核心操作:旋轉、Splay、查找第 k 個、區間分離
void rotate(int x, int &k) { ... }
void splay(int x, int &k) { ... }
int find(int k, int rank) { ... } // 查找第 rank 個節點
void split(int l, int r) { // 將 [l, r] 區間暴露在 key 位置
int x = find(rt, l-1), y = find(rt, r+1);
splay(x, rt); splay(y, c[rt][1]);
}
| 操作 | Splay 實現策略 |
|---|---|
| Move k | 直接記錄光標位置 pos = k+1(+1 因頭哨兵) |
| Insert n | Split(pos+1, pos) → 構建新子樹掛在 key 位置 → PushUp |
| Delete n | Split(pos+1, pos+n) → 斷開 key → PushUp |
| Get n | Split(pos+1, pos+n) → 中序遍歷 key 輸出 |
| Prev/Next | pos-- / pos++(配合邊界檢查) |
| Rotate n | Split(pos+1, pos+n) → 將最後一個節點斷開插到區間首 |
題目數據包含可見字符及空格,行尾無空格。關鍵點:
scanf("%d%*c", &n) 跳過換行符(%*c 讀取不賦值)fgets 或逐字符 getchar() 讀取保留空格scanf("%s", op) 讀取首單詞判斷類型本題是 Splay 树維護區間操作的經典模板題。關鍵在於:雙哨兵簡化邊界、split 統一區間暴露、懶標記處理翻轉、構建平衡樹初始化。掌握此模式可解決動態序列區間查詢/修改大類問題。