東京大学プログラミングコンテスト2013 I - 支配と友好

,

なんとなく、こどふぇすの動画(続・ペアプログラミング)を見て、一緒に書いた。

I - 支配と友好

解説

https://www.youtube.com/watch?v=jotn1-RzOC0を見よう。

euler tourで説明されているが、グラフを平面描画して左側と右側に分けてそれぞれ求めている、とも言える。 そもそもeuler tourと平面描画ってちょっと似てる気もする。

実装

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include <functional>
#include <climits>
#define repeat(i,n) for (int i = 0; (i) < (n); ++(i))
using namespace std;
template <typename T> bool setmin(T & l, T const & r) { if (not (r < l)) return false; l = r; return true; }
int main() {
    int n; cin >> n;
    vector<int> a(n); repeat (i,n) cin >> a[i];
    vector<vector<int> > g(n), rev(n);
    repeat (i,n-1) {
        int s, t; cin >> s >> t;
        g[  s].push_back(t);
        rev[t].push_back(s);
    }
    int root; repeat (i,n) if (rev[i].size() == 0) root = i;
    vector<vector<int> > cands(n);
    set<int> vs;
    function<void (int, int)> dfs = [&](int i, int p) {
        auto it = vs.upper_bound(a[i]);
        if (it == vs.end()) {
            if (not vs.empty()) cands[i].push_back(* vs.rbegin());
        } else {
            cands[i].push_back(* it);
            if (it != vs.begin()) cands[i].push_back(* -- it);
        }
        for (int j : g[i]) if (j != p) dfs(j, i);
        vs.insert(a[i]);
    };
    dfs(root, -1);
    repeat (i,n) reverse(g[i].begin(), g[i].end());
    vs.clear();
    dfs(root, -1);
    repeat (i,n) {
        pair<int,int> ans = { INT_MAX, -1 };
        for (int cand : cands[i]) {
            setmin(ans, make_pair(abs(cand - a[i]), cand));
        }
        cout << ans.second << endl;
    }
    return 0;
}