P4092 [HEOI2016/TJOI2016]樹
阿新 • • 發佈:2022-03-05
題面
在 2016 年,佳媛姐姐剛剛學習了樹,非常開心。現在他想解決這樣一個問題:給定一顆有根樹,根為 \(1\) ,有以下兩種操作:
-
標記操作:對某個結點打上標記。(在最開始,只有結點 \(1\) 有標記,其他結點均無標記,而且對於某個結點,可以打多次標記。)
-
詢問操作:詢問某個結點最近的一個打了標記的祖先。(這個結點本身也算自己的祖先)
你能幫幫她嗎?
思路
1.暴力圖遍歷
可以考慮建反圖,然後標記用一個數組維護,詢問則以該節點為源點,像下(原圖為上)跑DFS遍歷,直到 遍歷到被標記的節點即可。
由於是樹,所以不會出現死迴圈的情況。
最壞時間複雜度為 \(O(nq)\)。
#include <bits/stdc++.h> #define SIZE ((int(1e5))+5) using namespace std; int n, q, ec, juli = INT_MAX, ans; int head[SIZE]; int tag[SIZE]; struct edge { int next, to; } edges[SIZE]; void add(int from, int to) { edges[++ec].next = head[from]; edges[ec].to = to; head[from] = ec; } void dfs(int u, int ndeep) { if (tag[u] > 0 && juli > ndeep) { ans = u; juli = ndeep; } for (int j = head[u]; j; j = edges[j].next) { int v = edges[j].to; dfs(v, ndeep + 1); } } int main() { cin >> n >> q; for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; add(v, u); } tag[1] = 1; while (q--) { char op; int u; cin >> op >> u; if (op == 'C') { tag[u] = 1; } else { dfs(u, 0); cout << ans << endl; juli = INT_MAX; } } }
能水68分。