live archive 5021 Tree Representation
Tree Representation
問題概要
木が与えられる。
木のノードには1からnまで名前が付いている。
エッジに重みはない。
以下の手順をノードが二つになるまで繰り返す。
- 最小の葉ノードを選び消す
- 今消したノードの親を記録する。
この処理を繰り返した記録がある。
木を復元せよ。
解法
まず、記録にないノードはすべて最初の時点で葉である。
それが、現時点で葉である可能性があるノードの厳密な集合である。
(残り二個まで消すので子をもっているなら必ず登場する)
そして、最初に消えるのはその集合の中で一番小さなノードである。
そして、そのノードの親が記録されているのである。
その親番号がそれ以降に存在していなければ、それは葉になったと考えてよい。
(再帰的に部分木においても先述の法則は成り立つ。)
それを繰り返せば、各ノードの親がわかり、木を復元することができる。
ソース
#include<iostream> #include<algorithm> #include<vector> #include<cstdlib> #include<cmath> #include<set> #include<cassert> #define REP(i, b, n) for(int i = b; i <(int)n; i++) #define rep(i, n) REP(i, 0, n) #define FOR(it, o) for(__typeof((o).begin()) it = (o).begin(); it != (o).end();++it) using namespace std; int main(){ int T; cin >> T; rep(tc, T){ if(tc != 0)cout << endl; int n; cin >> n; int in[n]; set<int> L; rep(i, n){ L.insert(i+1); } rep(i, n-2){ cin >> in[i]; if(L.find(in[i]) != L.end())L.erase(L.find(in[i])); } int p[n+1]; rep(i, n+1)p[i] = -1; int now = 0; while(1){ int mini = *(L.begin()); L.erase(L.begin()); p[mini] = in[now]; now++; if(now == n-2)break; bool last = true; REP(i, now, n-2){ if(in[i] == in[now-1])last = false; } if(last)L.insert(in[now-1]); } vector<int> left; REP(i, 1, n+1){ if(p[i] == -1){ left.push_back(i); } } assert(left.size() == 2); p[left[0]] = left[1]; set<int> res[n+1]; REP(i, 1, n+1){ if(p[i] == -1)continue; res[i].insert(p[i]); res[p[i]].insert(i); } REP(i, 1, n+1){ cout << i ;//<< ' '; FOR(it, res[i]){ cout << ' ' << *it; } cout << endl; } } }