高程昱
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- tags: Training, 2022WinterTraining, ACP title: Tree Centroid Decomposition & Tree Hash type: slide slideOptions: # transition: fade --- <style> .reveal .slides { text-align: left; font-size:33px; } </style> ## Centroid Decomposition & Tree Hash --- ## Centroid Decomposition 重心剖分 (樹分治),透過每次不斷找到當前子圖的重心,重心拔掉再遞迴下去分割的子樹找各自的重心 重心的定義為一棵樹把節點 $G$ 移除之後,其最大的連通塊會是最小的,而我們會稱節點 $G$ 是樹重心。 ---- ## 如何找到樹重心 先選一個點為根節點,暴力 $O(n)$ 跑過所有節點紀錄每個節點的子樹大小 $s_i$。 假設子樹大小分別為 $s_1, s_2,... s_k$,則父節點方向的子樹大小為 $n - 1 - \sum{s_i}$ 樹重心為 max(n-1-$\sum{s_i}, s_1, s_2...s_k)$ 中最小的節點 ---- ## 重心的性質 - 把重心拔掉之後, 所有子樹的大小會 $\le\frac{n}{2}$ - 一棵樹最多兩個樹重心 ---- ## 重心剖分 1. 找到樹重心 2. 把樹重心從圖上移除 3. 遞迴下去連到的子圖 4. 如果子圖大小 >1 回到步驟 1 ![](https://i.imgur.com/scl8ghu.png) ---- 找到<span style = "color:red;">樹重心 </span> ![](https://i.imgur.com/9eqXdSp.png) ---- 把樹重心從塗上移除,剩下的子圖分別去找各自的樹重心 ![](https://i.imgur.com/FSKOW60.png) ---- 找到子圖各自的<span style = "color:orange;">樹重心 </span> ![](https://i.imgur.com/c47NCd7.png) ---- 把樹重心移除,剩下的子圖分別去找個字的樹重心 ![](https://i.imgur.com/LXrxUzN.png) ---- 找到各自的<span style = "color:green;">樹重心 </span> ![](https://i.imgur.com/cp4eK8v.png) ---- ## 複雜度 每次把圖從重心分割,每個子圖最大為原本的一半 最多遞迴 $\log N$ 層 $T(n)=\sum T(s_i) + O(n)$ 複雜度 $O(N\log{N})$ ---- ## 重心樹 對於當前這層的重心與下一層子圖的重心連接可以構出一顆重心樹 由於重心剖分的性質,樹高度不超過 $\log n$ ![](https://i.imgur.com/cp4eK8v.png) $\to$ ![](https://i.imgur.com/IWJ2yGG.png) ---- ![](https://i.imgur.com/cp4eK8v.png =x300) $\to$ ![](https://i.imgur.com/i87ocvA.png =x300) ---- ## 引入例題 CF 342 E. Xenia and Tree 給你 $n$ 個節點的樹,一開始每個點都是藍色,會有 $m$ 次操作 - 把某個藍點塗成紅色 - 查詢某個點最近的紅點有多遠。 $n, m\le 10^5$ ---- $n, m\le 10^5$ 如果暴力做,直接用一個陣列紀錄每個節點的顏色 - 把某個藍點塗成紅色 $\to$ O(1) 更新某個節點的顏色 - 查詢某個點最近的紅點 $\to$ BFS 找最近的紅色節點 $O(n)$ 很明顯如果每次都是第二種操作,總複雜度為 $O(nm)\to$ TLE ---- ### 換一種作法 先選一個節點為根 每個節點紀錄到子樹中最近的紅色節點距離,沒有則視為無限大 1. 把某個藍點 $v$ 塗成紅色 - 從當前節點 $v$ 開始往根節點方向更新所有祖先的距離 ![](https://i.imgur.com/4we3zrp.png =x300) ---- 2. 查詢某個點 $v$ 最近的紅點 - 從當前節點 $v$ 開始往上走 - 每次判斷到某個祖先 $u$ 的距離 + 祖先 $u$ 到他最近的子樹紅色節點距離取最短的 ![](https://i.imgur.com/QxTPRRw.png =x300) ---- 1. 把某個藍點 $v$ 塗成紅色 - 從當前節點 $v$ 開始往根節點方向更新所有祖先的距離 2. 查詢某個點 $v$ 最近的紅點 - 從當前節點 $v$ 開始往上走 - 每次判斷到某個祖先 $u$ 的距離 + 祖先 $u$ 到他最近的子樹紅色節點距離取最短的 以上兩種 case 只要到根節點距離很遠複雜度就變 $O(n)$ 一樣最差會變成 $O(nm)$ ---- ### 但如果樹是平衡的 ? 如果樹高最高為 $\log n$ 1. 把某個藍點 $v$ 塗成紅色 - 從當前節點 $v$ 開始往根節點方向更新所有祖先的距離 2. 查詢某個點 $v$ 最近的紅點 - 從當前節點 $v$ 開始往上走 - 每次判斷到某個祖先 $u$ 的距離 + 祖先 $u$ 到他最近的子樹紅色節點距離取最短的 則複雜度變成 $O(m \log n)$ ---- ## 用剛剛的重心樹 ? 會發現重心剖分建出來的重心樹樹高最差為 $\log n$ ![](https://i.imgur.com/cp4eK8v.png =x300) $\to$ ![](https://i.imgur.com/i87ocvA.png =x300) ---- ### 把節點 $v$ 塗成紅色 用 mn 陣列紀錄子樹中最近的紅色節點距離,沒有則視為無限大 對於每一次塗色,從當前節點往祖先方向走到重心樹根節點 更新從塗色節點 $v$ 到當前走訪到的節點 $u$ 距離是否為更近的紅色節點 mn[u] = min(mn[u], dis(u, v)) ---- 以塗色節點 5 為例 ![](https://i.imgur.com/4we3zrp.png =x300) ![](https://i.imgur.com/cp4eK8v.png =x300) 會更新節點 5, 4, 1 到紅色的最短 ---- ### 詢問節點 $v$ 到最近紅色節點距離 從當前節點往重心樹根節點方向走 每次問走訪到的節點 $u$ 與詢問節點 $v$ 的距離+走訪到的節點 $u$ 到子樹中最近的紅色節點距離 ans = min(ans, dis(u, v) + mn[u]) ---- 詢問節點 7 到紅色最短 ![](https://i.imgur.com/QxTPRRw.png =x300) ![](https://i.imgur.com/cp4eK8v.png =x300) 答案會是 ```txt= min( 節點 7 到最近紅色點距離, 節點 1 到最近紅色點距離 + 節點 1 到節點 7 的距離) = min(∞, 2+2) = 4 ``` ---- ### 為甚麼這樣是好的 ? 只更新從當前節點到重心樹根結點路徑上的距離,其他節點呢 ? 可以分成兩種 case : 1. 最近的紅色節點在重心樹的子樹中 2. 最近的紅色節點在往根節點方向 ---- #### 1. 最近的紅色節點 $u$ 在重心樹的子樹中 如果節點 $u$ 在詢問節點 $v$ 的子樹中 則在塗色時已經更新過詢問節點 $v$ 到最近紅色節點的距離 因此答案為 mn[v] = dis(u, v) ---- #### 2. 最近的紅色節點 $u$ 在往根節點方向 則到最近的紅色節點必定會先經過詢問節點 $v$ 的某個祖先 $a$ 因此答案為祖先 $a$ 的子樹中最近的節點 + 自己到祖先 $a$ 的距離 mn[a] + dis(a, v) ---- ### 複雜度 每次會從當前節點走到重心樹的根節點 每次會計算樹上兩點之間的距離更新最近距離 由於樹高不超過 $\log n$ 算樹上兩點之間的距離可以 $O(\log n)$ 找 lca, 再透過深度 dep[u]+dep[v]-2*dep[lca] 得到 因此每次操作的複雜度為 $O(\log^2n)$ 總複雜度為 $O(m\log ^2n)$ ---- ### 細節 注意計算距離是算原本那棵樹上的距離 ---- ### 另外一個例題 CSES. Fixed-Length Paths I 給一棵 $N$ $(1\le N\le 2\cdot 10^5)$ 個節點的無根樹,樹上有幾個點對的距離為 $k$ 也就是有幾個長度為 $k$ 的簡單路徑 ---- ### 考慮分治 選一個點 $v$ 計算所有經過他且長度為 $k$ 的路徑 把點 $v$ 拔掉再分成各自的連通子圖遞迴下去計算長度為 $k$ 的路徑 ---- ![](https://i.imgur.com/6IXgNYL.png =400x) 經過當前點 $v$ 的且長度為 $k$ 的路徑分成兩種 1. 以當前點 $v$ 為起點往外的路徑 2. 經過當前點 $v$ 的且不為起始點的路徑 ---- 1. **以當前點 $v$ 為起點往外的路徑** 第一種我們可以從點 $v$ 開始 DFS 紀錄從點 $v$ 到當前節點的長度,如果長度為 $k$ 則答案 + 1 ```cpp= auto dfs = [&](int x, int f, int d) -> void{ if(d == k) ++ans; for(int i : edge[x]){ if(i == f || vis[i]) continue; dfs(i, x, d+1); } }; for(int i : edge[v]){ dfs(i, v, 1); // 遞迴從 v 連出去的節點 i } ``` ---- 2. **經過當前點的且不為起始點的路徑** 第二種等價於從點 $v$ 開始往兩棵相異子樹方向長度分別為 $a, b$ 且 $a+b = k$ 的路徑 我們可以算往某個子樹長度為 $a$ 的路徑有幾個,乘上往其他子樹路徑長度為 $k-b$ 有幾個。 每個子樹都去計算即為答案 ---- 每次從點 $v$ 開始往不同的子樹去遞迴,計算每個子樹當前走到的距離 $d$ 與前面計算過有幾個距離為 $k-d$ (儲存在 cnt 陣列裡) 算完之後再把當前子樹的距離加進去 cnt 陣列裡 ```cpp= auto dfs = [&](int x, int f, int d, bool add) -> void{ if(d == k){ //case 1 ans++; return; } if(add) ans += cnt[k - d]; else cnt[d]++; for(int i : edge[x]){ if(i == f || vis[i]) continue; dfs(i, x, d+1, add); } }; fill(cnt, cnt+sz, 0); for(int i : edge[v]){ dfs(i, v, 0, 0); // 計算完當前子樹的距離與前面窮舉過的距離加進答案 dfs(i, v, 0, 1); // 把當前子樹的距離存進去 cnt } ``` ---- 每次選一個節點 $v$ 計算經過他且長度為 $k$ 的路徑 再把節點 $v$ 要怎麼選會是最好的 ? 每次選節點 $v$ 計算長度為 $k$ 的路徑複雜度最差為 $O(n)$ 如果選重心? ---- 回想一下重心剖分的複雜度計算 $T(n)=\sum T(s_i) + O(n)$ 每次會跑過當前連通塊所有節點,找到重心之後把重心拔掉 再繼續遞迴下去 --- ## Tree Hash 根據樹的形狀把整棵樹 Hash 成一個值。 進而可以 `O(1)` 判斷兩棵樹是否為同構 ---- ## isomorphism 同構圖的定義為給定兩張圖其節點數量相同,且在兩張圖重新編號後能夠使得任兩個點對其連邊狀況相同 ![](https://i.imgur.com/53NG3In.png =300x) ![](https://i.imgur.com/ULch3qY.png =300x) 上兩張圖為同構圖,把左邊那張編號為 3, 4 的節點交換編號後,其任一點對連邊狀況相同 ---- ## Rooted Tree Hash 給定兩棵有根樹,判斷是否為同構的有根樹 ![](https://i.imgur.com/gQJvJTt.png =x300) ![](https://i.imgur.com/dTLX5We.png =x300) 以上為同構有根樹,每個節點的子節點可以重新排列順序後相同 ---- ## 作法 rolling hash on tree hash(u) = $\sum$ hash$(v)\times p^i$ % mod 1. 算出每個子樹 $v$ 的 hash 值 2. 把所有子樹 $v$ 的 hash 值排序 3. 依序把每個子樹 $v$ 的 hash 值加入計算 *葉節點的 hash 值為 1 ---- 1. 算出每個子樹的 hash 值 2. 把所有子樹的 hash 值排序 3. 依序把每個子樹的 hash 值加入計算 ```cpp [|2-5|6|7-10|] ll dfs(int u){ vector<ll> h; subtree_sz[u] = 1; for(ll child : edge[u]){ h.push_back(dfs(child)); subtree_sz[u] += subtree_sz[child]; } sort(h.begin(), h.end()); ll ret = subtree_sz[u]; for(ll v : h){ ret = (ret * base + v) % MOD; } return ret; } ``` ~~如果過不了就多拿幾個參數 hash,反正通常都在亂做~~ ---- ## 複雜度 每個節點只遍歷一次,每次只排序自己的子節點 hash 值 $O(NlgN)$ ---- ### 2020 ICPC Taipei region --- Problem G. Graph Cards 判斷有幾種不同構的水母圖 (簡單環 + 環上點連出去樹 ) ![](https://i.imgur.com/ARqDpo8.png) - $\sum n\le 10^6$ ---- ## 作法 先找環 相信大家都會做 ? ---- ## 作法 把環上連出去的樹分別去做 hash 把所有環上的每棵樹縮點成整棵樹的 hash 值 ![](https://i.imgur.com/9KZjImy.png =300x) 題目轉換等價於求 幾種不同構的環狀序列 ---- 幾種不同構的環狀序列 ? [minimum rotation](https://github.com/jakao0907/CompetitiveProgrammingCodebook/blob/master/string/minRotation.cpp) ! 轉一下序列,把序列變成最小字典序為開頭 即可比較兩個環狀序列是否相同 模板 minimum rotation 可以 $O(N)$ 做到求出最小字典序旋轉 函數會回傳要把哪個位置當成開頭 內建函數 rotate() 可以幫你旋轉不用自己轉 --- ## 無根樹判斷同構? 由於一棵樹的重心最多只有兩個,因此我們可以直接用重心當根 去做有根樹 hash 判斷兩棵樹是否為同構只需要判斷兩個重心的 hash 值是否相同即可 --- ### Question Time and Practice [Homework Link](https://vjudge.net/contest/535249) 提交期限到 1/13 23:59 截止 ---- ## 本學期課程結束 ! 相信大家都收穫滿滿 ? <div style="font-size:10px"> <div style="position: absolute; right: 10%;"> - Tree - Lowest Common Ancestor - DP on Tree - DSU on Tree - Heavy-Light Decomposition - Centroid Decomposion - Tree hash - Graph - BFS/DFS - Topological Sort - Shortet Path - DSU & MST - SCC/BCC - 2-SAT - Eulerian Path - LCA - String - Trie - Hash - KMP - Manacher - Palindrome tree - Z value - Suffix array - Geometry - Convex hull construction - Sweep Line - Flow & Matching - Flow Construction </div> - Brute Force Search - Backtracking - Memory Search - Meet In the Middle - Math - Modulo Operation - Modular Multiplicative Inverse - Prime - Dynamic Programming - DP on DAG - Stack / Deque - Bitmask DP - 1D/1D Dynamic Programming - Convex hull optimization - Data Structure - Segment Tree - BIT - Sparse Table - Treap - Persistent Data Structure - PBDS - Square Algorithm - Square Root Decomposition - Mo's Algorithm - Game - SG value </div> ---- 希望大家對於之後演算法設計、程式實作、面試等等都會有幫助 並不是只是一個三學分的課而已 之後在寫程式前都能先好好分析複雜度、想想學過的演算法是否可以用上 祝大家聖誕節快樂 :gift: ---- 期末考 1/6 6:30 大家記得來考 : ) 考試內容:練習賽題目、這幾周上課內容

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully