每次詢問可以給出一個點集,系統會返回點集中距離點 s 和點 t 距離之和最小的那個點以及其距離,如果有多個符合條件的點,會返回任意一個,比如詢問了點集 A = { s1 , s2 , ... , sk } ,則系統會返回一個點 v ∈ A 并且 dist( s , v ) + dist( t , v ) 最小
首先因為無從下手,所以可以先問一遍全部的點,獲得到一個點 rt ,且距離之和為 len,畫畫圖應該不難看出,點 rt 滿足的一個性質是,一定位于點 s 到點 v 的這條路徑上
下面的轉換可能比較難想,但是如果想到了的話剩下的就比較簡單了
我們可以以點 rt 點為根,遍歷一遍整棵樹后跑出每個點的深度,此時對于每個點的深度以及 dist( s , v ) + dist( t , v ),可以看出這兩個值之間滿足著單調性,這樣我們就可以在深度上二分找到:距離之和等于 len 的最大深度的那個點,這個點就是 s 或者 t 中的一個點,再用找到的這個點建樹,詢問深度為 len 的那一層的所有點,得到的答案就是另外一個點了
如果初始時設置 l = 1 , r = n ,那么 F1 就這樣解決了,主要是該如何解決 F2?
很顯然,詢問全部的 n 個點,和知道其中一個點后再通過一次操作得到另外一個點,這兩次操作是無可避免的,優化點只能出自于二分上面 ,對于二分,我們可以做的優化就是縮小初始的范圍了
因為初始時找到的 rt 一定是位于 s 到 t 的路徑上的,又因為我們是要借助二分尋找距離之和等于 len 的最大深度,那么當這個 rt 在 s 到 t 這條路徑的最中間時,左端點最小,取到了??的位置,相應的,我們如果假設 rt 這個點初始時就是 s 點或者 t 點的話,那么右端點最多也就是 len 了,所以右端點我們設置為 min( len , max_deep ) 就好了,max_deep 是建樹后的最大深度