水母上 Divide-and-Conquer
一棵樹有「拔掉任一非葉節點便不連通」的良好性質,可以幫助我們用 DP 和 divide-and-conquer 解決問題,例如 POJ 1741 和 TIOJ 1647。這篇假定你知道怎麼把 POJ 1741 做到 O(n(logn)2) 的時間複雜度 (如果你不知道也沒關係,google "POJ 1741" 就有很多資料了 XD)。我們沿用先前的定義,把一張點數和邊數相等的連通近圖 (pseudograph) 稱作一隻水母。再次提醒,水母並不是正式名稱 (我找不到正式名稱 orz)。
考慮這個問題:給定一隻大小為 n 的水母 J=(V,E),邊有正權重,請求出 J 的 K-近對個數。一個 K-近對的定義是距離不超過 K 的 (無序) 點對。觀察到一隻水母其實是由頭部 (環) 和數條觸手 (樹) 組成。設頭部由點 t0,t1,…,tm−1 組成,從 ti 長出的觸手為 Ti。我們把 K-近對 (u,v) 分成兩種:u,v 屬於同一條觸手 (α 型)、u,v 屬於不同條觸手 (β 型)。只要在每條觸手上跑 POJ 1741,就能求出 α 型 K-近對個數了。至於 β 型,做法是對於每個點 v,統計有幾個點 u 滿足
那麼要怎麼統計有幾個 u 滿足 du+dv+(si−sj)≤K 呢?固定 v,我們想知道的其實是有幾個 u 滿足 du−sj≤K−dv−si。如果我們有一棵 binary search tree 儲存 du−sj 們,就能在 O(logn) 時間內得到答案。統計完 v∈Ti 後,換統計 v∈Ti+1,此時 Ti 裡的 du−si 們可以加進 BST 中;另一方面,可能有些 j 變成 si+1−sj>sm/2,必須把這些 Tj 裡的 du−sj 們從 BST 踢掉。詳細部分可以參考下面這份 pseudocode:
計算 α 型 K-近對個數需要 O(n(logn)2) 時間,而計算 β 型 K-近對個數需要 O(nlogn) 時間 (對 BST 插入 2n 次、查詢 n 次、與刪除不超過 2n 次),因此整體的時間複雜度只有 O(n(logn)2)。
這題可以在 ZJ a666 測。
考慮這個問題:給定一隻大小為 n 的水母 J=(V,E),邊有正權重,請求出 J 的 K-近對個數。一個 K-近對的定義是距離不超過 K 的 (無序) 點對。觀察到一隻水母其實是由頭部 (環) 和數條觸手 (樹) 組成。設頭部由點 t0,t1,…,tm−1 組成,從 ti 長出的觸手為 Ti。我們把 K-近對 (u,v) 分成兩種:u,v 屬於同一條觸手 (α 型)、u,v 屬於不同條觸手 (β 型)。只要在每條觸手上跑 POJ 1741,就能求出 α 型 K-近對個數了。至於 β 型,做法是對於每個點 v,統計有幾個點 u 滿足
- u 和 v 不在同一條觸手上
- u,v 的距離 d(u,v)≤K
- 有可能 i<j
- 即使 i>j,可能 si−sj>sm/2,也就是 d(ti,tj)=sm−(si−sj)<si−sj
那麼要怎麼統計有幾個 u 滿足 du+dv+(si−sj)≤K 呢?固定 v,我們想知道的其實是有幾個 u 滿足 du−sj≤K−dv−si。如果我們有一棵 binary search tree 儲存 du−sj 們,就能在 O(logn) 時間內得到答案。統計完 v∈Ti 後,換統計 v∈Ti+1,此時 Ti 裡的 du−si 們可以加進 BST 中;另一方面,可能有些 j 變成 si+1−sj>sm/2,必須把這些 Tj 裡的 du−sj 們從 BST 踢掉。詳細部分可以參考下面這份 pseudocode:
這題可以在 ZJ a666 測。
留言
張貼留言