非持久化資料結構一般需要維護資料集最新狀態,而可持久化要求查詢歷史狀態。
可持久化Trie樹
樸素:每次修改重新存一遍 \(-> MLE\)。
正解:只存被修改部分,其餘不變,即第 \(i\) 次修改後,樹變為第 \(i\) 次修改產生新的部分加上前 \(i-1\) 次修改產生部分。
增長同規模。
用普通線段樹維護,\(m\) 次操作,時間複雜度 \(O(4n+mlog_n)\)。
可持久化線段樹
例:單點修改,查詢區間最大值
將 \(a[x]\) 加上 \(d\),從表示 \(x\) 位置的葉子節點修改到根
修改時,對所有會被修改的點重開一樹,樹上未修改的點與新圖父親連邊,被修改的點複製連邊
更新 \(p\) 節點時,若 \(p\) 不為葉子,則其左右兒子之一也會被修改
假設 \(ls\) 被更新,\(ls\) 遞迴時,令 \(p'\) 左兒子為 \(ls'\),右兒子為 \(rs\)
空間複雜度 \(O(4n+mlog_n)\)
由於樹中每個點只有一個父親,而可持久化線段樹有多個根,所以只能用動態開點的方法編號
主席樹(可持久化權值線段樹)
區間第 \(k\) 小:
\(root[r]->\) 在值域區間 \([x,y]\) 的 \(cnt_1\) 值
\(root[l-1]->\) 在值域區間 \([x,y]\) 的 \(cnt_2\) 值
插入次序在 \([l,r]\) 之間,且值域在 \([x,y]\) 之間數字個數:\(cnt_1-cnt_2\)
第 \(i\) 棵線段樹儲存從第一次插入到第 \(i\) 次插入資訊
序列問題 \(->\) 樹上問題
\(tree[i]\) 表示從根節點到 \(i\) 的路徑上資訊(值域上區間和)
\(tree[u]+tree[v]-tree[lca]-tree[fa(lca)]\)
區間第 \(k\) 小(帶單點修改):
線段樹看成樹狀陣列上一元素
設樹狀陣列中下標 \(i\) 所記錄資訊集合為 \(S_i\),那麼我們定義線段樹 \(T_i\) 是維護 \(S_i\) 內資訊的所有點的集合