Statement
樹,給 \(m\) 條帶權路徑 \((a,b,v)\),\(q\) 次詢問包含 \((u,v)\) 的路徑中的第 \(k\) 小權值.
Solution
好題!這篇題解延伸出了很多東西。
首先路徑的包含關係轉為矩形(二維限制關係)是比較顯然的.
具體地,\((u,v)\) 包含 \((a,b)\) 有兩種情況:
- \(u,v\) 無祖先關係:\(a\) 在 \(u\) 子樹內,且 \(b\) 在 \(v\) 子樹內,寫出來就是 \(\text{dfn}(u)\le\text{dfn}(a)\le\text{dfn}(u)+\text{siz}(u)-1\) 且 \(\text{dfn}(v)\le\text{dfn}(b)\le\text{dfn}(v)+\text{siz}(v)-1\).
- \(u,v\) 有祖先關係:設 \(u\) 為 \(v\) 祖先,\(w\) 為 \(u\to v\) 路徑上的第二個點(\(u\) 向 \(v\) 方向的第一個兒子),則有 \(a\) 在 \(v\) 子樹內,且 \(b\) 在 \(w\) 子樹外,寫出來:\(\text{dfn}(v)\le\text{dfn}(a)\le\text{dfn}(v)+\text{siz}(v)-1\) 且 \(1\le\text{dfn}(b)\le\text{dfn}(w)-1\) 或 \(\text{dfn}(w)+\text{siz}(w)\le\text{dfn}(b)\le n\).
注意到這樣的 \((a,b)\) 的取值範圍就是矩形,第二種情況是兩個矩形,然後這是一步轉化.
然後現在是 \((u,v)\) 被包含,也即問題變成了求包含一個點的權值第 \(k\) 小矩形.
這怎麼做呢,一種顯然的方法是整體二分:一次二分 \(x\) 就把所有權值 \(\le x\) 的矩形加入,判斷這個點被包含了多少次.
那如果我把題改成強制線上怎麼辦呢!!!
先不考慮強制線上,我們可以把每個詢問點離線下來排序,問題變成了需要支援區間插入一個數、區間刪除一個數、單點查第 \(k\) 大.
一看就很樹套樹,那假裝我們使用外層線段樹、內層平衡樹,考慮標記永久化,發現是三 log 的.
具體地,對於區間插入,我們找到外層線段樹上 \(\log\) 個點,對這 \(\log\) 個點進行插入,刪除類似. 這樣他們兒子沒有應用到這些更新,怎麼辦呢,你查一個葉子時,找出它以及它的所有 \(\log\) 個祖先,對這 \(\log\) 棵平衡樹求他們並起來的第 k 大.
眾所周知,這隻能最外層二分、用排名之和判定來做(二逼平衡樹),這樣修改是雙 log、查一次是三隻 log 的,甚至不如整體二分!!!
怎麼辦呢,我們發現問題在於多棵平衡樹無法一起二分,那我們改成外層線段樹、內層權值線段樹.
這樣,還是同樣地標記永久化,對於區間插入,對內層 \(\log\) 棵權值線段樹進行單點加,區間刪除類似;對於單點查,我們同樣地拎出根到葉子路徑上 \(\log\) 棵權值線段樹,發現這時就可以多棵權值線段樹一起二分了,複雜度降為雙 log.(也可參考二逼平衡樹的多種做法的對比)
這樣我們就做完了離線問題,那強制線上怎麼辦呢?
發現直接持久化一下就行了,(可持久化樹套樹,參考 bzoj3489),時間並未增加,空間升為雙 log.
具體怎麼做呢,假如我們已經可以持久化了,那我們把掃描線的過程持久下來,線上詢問直接在對應版本詢問即可;
發現外層持久化是容易的(只維護內層線段樹的根),而外層複製一次節點,內層線段樹肯定不能全部複製,發現因為是單點修改,還是隻複製發生更改的節點即可,然後做完了.
那如果是區間插入、區間刪除、區間查第 k 小,可以離線,怎麼辦呢!!!
發現外層線段樹區間查詢,經過的點數是 \(\log\) 級別的,然後把這些點拿出來一起二分就行了.
強制線上是一樣的,複雜度都沒有增加.
那我們迴歸到原問題,我常數太大了怎麼辦!!!
嘗試把外層線段樹改成樹狀陣列,區間插入、刪除可以轉化為字首插入、刪除,單點查可以變成兩段字首相減得到的樹的 kth,這同樣是單 log 的.
發現這樣可以擴充套件到區間查詢.
然後樹狀陣列理論上是可以持久化的……
當然還有其他各種做法,比如 K-D Tree,樹上莫隊 + 值域分塊等等。
總結:一道題的價值不僅在於過掉它,更是在於要總結方法、結論、trick 和規律,完善你的思考、思維方式,更好的是你透過這道題進行延伸、溫故而知新,比如想他的加強版可不可以這樣做,如果不行還能怎樣做,這樣就可以自己出題目,可以為師矣!