東京大学プログラミングコンテスト2013 I: 支配と友好
解法
2回オイラーツアーするだけ。勝手に根が0だと思い込んで(しかもサンプルがそれで合う)メッチャハマった。
コード
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int INF = 1e9 + 7; vector<vector<int>> g; set<int> double_appear; vector<int> a; vector<pair<int, int>> ans; void dfs(int cur, int prev, bool left) { if (!double_appear.empty()) { auto it = double_appear.lower_bound(a[cur]); if (it != double_appear.end()) { ans[cur] = min(ans[cur], {*it - a[cur], *it}); } if (it != double_appear.begin()) { it--; ans[cur] = min(ans[cur], {a[cur] - *it, *it}); } } if (left) { for (int i = 0; i < g[cur].size(); ++i) { if (g[cur][i] == prev) continue; dfs(g[cur][i], cur, true); } } else { for (int i = g[cur].size() - 1; i >= 0; --i) { if (g[cur][i] == prev) continue; dfs(g[cur][i], cur, false); } } double_appear.insert(a[cur]); } int main() { cin.tie(0); ios::sync_with_stdio(false); ll N; cin >> N; a.resize(N); for (int i = 0; i < N; ++i) cin >> a[i]; g.resize(N); vector<bool> is_root(N, true); for (int i = 0; i < N - 1; ++i) { int s, t; cin >> s >> t; is_root[t] = false; g[s].push_back(t); g[t].push_back(s); } int root = -1; for (int i = 0; i < N; ++i) if (is_root[i]) { root = i; break; } assert(root >= 0); ans.assign(N, {INF, -1}); double_appear.clear(); dfs(root, -1, true); double_appear.clear(); dfs(root, -1, false); for (int i = 0; i < N; ++i) { cout << ans[i].second << "\n"; } }