【Codechef】B-Tree

題目描述

給出一棵n 個點的樹,邊權都爲1 ,以及m 個詢問,每一個詢問形式如下:

給出k 個點的集合S={a1,a2,,ak} ,以及每一個點的控制範圍rai
一個點p 稱爲被控制的,當且僅當xS,dis(x,p)rx
問有多少個點被控制。

n,Q5×104,k5×105


分析

part 1 簡化的問題

不妨先看當k=1 時,問題變成怎麼樣的了。

給出一棵樹,每次詢問距離點x 的距離小於r 的點的個數。

考慮點剖,每一個重心上存點剖子樹中所有點,按照離重心距離爲關鍵字建桶。
那麼只需要在點剖樹上,從x 往上跳,沿路統計答案就可以了。
但是注意可能會有重複計算。但是考慮點剖樹上某個點只有logn 個祖先,將它們記錄下來,逐個減去重複計算的就可以了。
時間複雜度O(log2n)
但是假如我們加入無用白點,那麼這裏可以O(1) 地解決重複問題(只考慮另外兩個兒子就可以了)
時間複雜度O(logn)

邊剖也是類似的,不過相對來說更加好寫一點。

part 2 原問題的分解

擴展到多點 虛樹

k>1 時,我們可以引入虛樹和控制範圍的概念,從而將原問題轉化。

虛樹的構建可以利用歐拉序,首先先將每兩個相鄰的關鍵點之間最近公共祖先都加入進去。然後維護一個棧,每加入一個點,就不斷退棧,直到棧頂是它的某個祖先,然後將棧頂與這個點連邊,最後將這個新點壓入棧。

首先先構建出這k 個點的虛樹,那麼虛樹中的每個點x ,它的控制範圍lx=max0y<nlydisx,y ,每個點的歸屬belongx 自然就是任意一個取得最大lxy
爲了統一,假如某個點不被控制,不妨將lx 賦爲0belongx 賦爲n
用spfa可以快速地計算出每個點的控制範圍。

然後問題的答案就等於虛樹上的每條邊的答案之和。

單條邊的處理方式

一條邊的答案正着算似乎不好處理,用所有的虛樹上點的控制範圍點數和,減去重複的部分,也可以得到原來的答案。

  • 性質一:設(x,y) 是虛樹上的一條邊,那麼當且僅當belongxbelongy 時,纔會在這條邊上出現重複。
    證明:顯然。
  • 性質二:對於滿足性質一的邊,存在唯一的zpath[x,y] ,使得path[x,z] 上的點都屬x 管劾,path(z,y] 上的點都屬y 管劾。
    證明:
    不妨令depx<depy ,那麼
    lxdis(x,z)lydis(z,y)
    lx(depzdepx)ly(depydepz)
    depx+depy+lxly2depz
    depx+depy+lxly2depz
    由上面這條式子,就可以知道z 唯一確定了一條邊之間兩個點的管劾範圍。

part 3 更深入的分析

u-v之間確定點z

通過這樣的劃分以後,我們計算答案的思路就變成下面兩步

  • 假如某個點在新圖中存在勢力範圍,那麼統計它勢力範圍內的點數,將其求和。

  • 對於每條兩個端點的統治勢力不同的點,計算它們重疊部分並減去之。

對於第一個問題,套用“簡化的問題”的思路,就可以簡單地解決了。
對於第二個問題,實際上就是要統計距離不在點z 子樹內,離z 距離小於等於lz 的點數,以及在z 的子樹中,離點z 的距離小於等於ludis(z,u) 的點數。

那麼對於第二個問題比較好的解決思路就是dfs序,因爲子樹都是dfs序中連續的一段,而不在子樹中必定是全段挖去中間的一小段。那麼我們只需要按dfs序構建主席樹,那麼就可以快速進行統計了。

那麼單次詢問的時間複雜度就是的時間複雜度O(klogn)

於是最終總的時間複雜度是O(nlogn+Qklogn)

發佈了114 篇原創文章 · 獲贊 4 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章