可能陸陸續續補完吧...咕咕咕
先貼一手, AcWing的全解析
完善程序
(2)(RMQ 區間最值問題)
題意描述得非常具體(嗯, 都是我當時在考場上沒學的東西)
前置知識
- 笛卡爾樹
- 歐拉序
- ST表
這邊貼幾個網址吧, 畢竟我本人也就為這個解析剛學.
搜索二叉樹-百度百科
笛卡爾樹-百度百科
笛卡爾樹-OI-WIKI
笛卡爾樹-blog
歐拉序
笛卡爾樹, 就是一個每個節點有兩個值, k 和 w.
其中一個(k)滿足搜索二叉樹的性質, 另一個(w)滿足堆的性質
這道題, 是將數組下標看作k, 將val看作w.
了解了歐拉序后, 因為歐拉序有一個性質, 點x和點y的lca一定在x和y的歐拉序之間更加准確的說是x最后出現的歐拉序到y最先出現的之間.
st表是運用了倍增的思想, 可以求區間最值的數據結構
首先, 總的說一下這道題的思路, 將區間最值問題轉換為LCA問題, 在用區間最值問題來求解LCA.(使用分塊的思想, 預處理, 最終降低了時間復雜度)
一開始建笛卡爾樹, 因為它要同時滿足兩個性質, 我們先按k排序(本題因為是以數組下標作為k, 不用排序, 遍歷即可), 因為k要滿足搜索二叉樹的性質, 后加入的k一定比前加入的k的值要大, 所以插入的地方只能在根節點的右鏈(包含根節點)上, 否則不滿足性質, 具體插在哪個位置, 是看哪個位置能夠滿足堆的性質, 及用w(本題的val)來比較, 若要滿足堆的性質要使得當前待插入的節點變為當前根節點的父節點, 就把當前根節點作為待插入點的左兒子
更好理解插入的操作, 我提供一張配圖
不難理解, 這樣的操作, 一定是滿足搜索二叉樹的性質, 而我們插入也一定可以找到一個位置使它滿足堆的性質(本題本質上是尋找右鏈上第一個比它小的節點位置, 實現方式為單調棧)
分析到這里建樹的函數的題就可以做出來了.
1.選A.
還沒找到就把當前彈出來的節點暫時任命為它的左兒子, 直到它找到第一個比它小的節點位置,
那時候while結束, 待插入節點的左兒子就定下來了.
所以這題選A.
2.選D
如果它不是變為根節點的父節點的話, 即top不為空的話, 就把它的上一個節點的右兒子變為待插入節點.
至此, 笛卡爾樹的建樹過程結束了.
由歐拉序的性質, 我們要查找的區間最值就轉變為了求x, y的lca, dfs跑完后, 我們要求的lca顯然是x,y之間的深度最小的點.
3.選A
后面的query等函數中調用min, 最后輸出的那個點對應的val,
所以這里的min是用來比較各個分塊后的塊內的lca的最小深度.
之后判斷區間內的lca其實所用的深度只要是區間內的相對深度即可,
因為相鄰的點的深度只有+-1關系,我們只要預處理出來每個塊內的峰值.
4.選D
由上面分析可得, Dif里存的是可能是x, y點之間的深度變化關系,
所以比較前后兩個歐拉序的深度.
5.選D
mx代表最小值, 容易判斷是深度的最小值.
這里是預處理出來每個塊中給所有可能的+-狀態, 直接預處理出來這個狀態的lca的位置,
結合第四題分析, 對v進行加減操作, 若深度小於最小值就更新最小值的點.
注意: 是i-1, 要觀察好前一個更新Dif的式子.
6.選C
通過后面的return值, 不難看出要求出[l, r]的lca的相對位置(后面加了偏移量l).
必須要移除l前的與r后數據, 因為求的是[l, r]的最小值.
所以先右移, 把l前的加減操作清除掉, 在和與長度為r-l+1的`11...11`做與操作就成功將[l, r]的操作取出.