# Codeforces 1790 Timofey and Black-White Tree ###### tags: `codeforces` `Tree` [題目連結](https://codeforces.com/contest/1790/problem/F) # 題目說明 給定一顆 N個節點的數, 起初有一個初始節點 c1 被染色 接下來 給 n-1個染色的節點, c2, c3, c4... cn 每次有新的染色節點時, 印出在這棵樹上任意兩個染色節點最短的距離. ex: ![](https://i.imgur.com/cCpzJXh.png) 染色節點 1, 6 其距離為 3 染色節點 1, 4 其距離為 2 因此在這三個染色點, 最短的距離為 2 :::info :bulb: **需要的知識**: 在一條長度為n的線段, 放置$\sqrt{n}$個節點, 兩兩之間的距離一定小於等於 $\sqrt{n}$ 也就是說 距離最大的情況為 $\sqrt{n}$ ![](https://i.imgur.com/mzZRcOT.png) 對於樹的結構, 也會有相同的特性, 在樹的節點, 擺放 $\sqrt{n}$ 的節點, 兩兩之間的距離一定小於等於 $\sqrt{n}$ ::: :::info :bulb: 特性 1 假如當前任意兩個染色節點最短距離為 x, 新的點加入時, 該節點到達其他染色距離 只要大於等於 x, 就表示該節點不會影響結果. ::: # Method DFS :::info :bulb: **作法講解**: 變數說明: min_dist: 維護其他染色節點到達 ith node 所需要的最短距離. output: 維護當前加入節點的最短距離. 一開始先使用DFS 遍歷 c1 節點 到所有節點的距離, 每次有新染節點(node)加入時, min_dist[node]的值就表示 node 到 其他最近的染色節點的距離. 更新 output = min(output, min_dist[node]) 然後再從node出發, 遍歷node附近的節點, 這邊需要特別注意, **case 1: 假如新的節點 x 與node 的距離 大於等於 min_dist[x], 表示前面有其他染色節點更靠近x.** **case 2: 假如新的節點 x 與node 的距離 大於等於 output, 即使更新了其min_dist[x],** **min_dist[x]對於最終結果也不會有影響** ::: TC: O(NlogN) SC: O(N) 完整程式碼 ```cpp= int nums[N]; vector<int> adj[N]; int min_dist[N]; void dfs(int node, int parent, int d, int &ans) { if ((d >= min_dist[node]) || (d >= ans)) { return; } min_dist[node] = d; for (int next : adj[node]) { if (next == parent) { continue; } dfs(next, node, d + 1, ans); } } void solve(int round) { int n, c; int a, b; int output = INT32_MAX; for (int i = 0; i < N; i++) { adj[i].clear(); } CLR(nums); SET(min_dist, 0x3f); cin >> n >> c; for (int i = 1; i < n; i++) { cin >> nums[i]; } for (int i = 0; i < n-1; i++) { cin >> a >> b; adj[a].push_back(b); adj[b].push_back(a); } dfs(c, -1, 0, output); for (int i = 1; i < n; i++) { output = min(output, min_dist[nums[i]]); printf("%d ", output); dfs(nums[i], -1, 0, output); } printf("\n"); } ```