Problem:
Score : 600 points

Problem Statement

We have a tree with N vertices. The vertices are numbered 1 to N, and the i-th edge connects Vertex a_i and Vertex b_i.

Takahashi loves the number 3. He is seeking a permutation p_1, p_2, \ldots , p_N of integers from 1 to N satisfying the following condition:

For every pair of vertices (i, j), if the distance between Vertex i and Vertex j is 3, the sum or product of p_i and p_j is a multiple of 3.

Here the distance between Vertex i and Vertex j is the number of edges contained in the shortest path from Vertex i to Vertex j.

Help Takahashi by finding a permutation that satisfies the condition.

Constraints

2\leq N\leq 2\times 10^5

1\leq a_i, b_i \leq N

The given graph is a tree.

Input

Input is given from Standard Input in the following format:

N
a_1 b_1
a_2 b_2
\vdots
a_{N-1} b_{N-1}

Output

If no permutation satisfies the condition, print -1.

Otherwise, print a permutation satisfying the condition, with space in between.
If there are multiple solutions, you can print any of them.

Sample Input 1

5
1 2
1 3
3 4
3 5

Sample Output 1

1 2 5 4 3

The distance between two vertices is 3 for the two pairs (2, 4) and (2, 5).

p_2 + p_4 = 6

p_2\times p_5 = 6

Thus, this permutation satisfies the condition.

Solution in C++14 (GCC 5.4.1) (judge verdict: Runtime Error)

#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>


using namespace std;
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;

#define REP(i,n) for(int i = 0; i < (int)(n); ++i)
#define FOR(i,a,b) for(int i = (a); i < (int)(b); ++i)
#define ALL(c) (c).begin(), (c).end()
#define SIZE(v) ((int)v.size())

#define pb push_back
#define mp make_pair
#define mt make_tuple

// 頂点は0-originとする
template <typename T>
class Dijkstra {
    struct edge { int to; T cost; };
    typedef pair<T, int> P; // <最短距離, 頂点番号>

private:
    int m_V;
    vector<vector<edge> > m_G;
public:
    const T INF = std::numeric_limits<T>::max();
    vector<int> m_prev_path; // 最短パスを辿るため

    Dijkstra(int V) : m_V(V) {
        m_G.resize(m_V);
    }

    // a -> bに片方向のエッジを張る
    void add_dir_edge(int a, int b, T cost) {
        m_G[a].push_back( edge{ b, cost } );
    }

    // a <-> bに両方向のエッジを張る
    void add_undir_edge(int a, int b, T cost) {
        add_dir_edge(a, b, cost);
        add_dir_edge(b, a, cost);
    }

    // 頂点sから各頂点までの距離を計算して返す
    vector<T> shortest_path(int s) {
        m_prev_path.clear(); m_prev_path.resize(m_V, -1);

        vector<T> d(m_V, INF);
        priority_queue<P, vector<P>, greater<P> > que;
        d[s] = 0;
        que.push(P(0, s));

        while(!que.empty()) {
            P p = que.top();
            que.pop();

            auto dist = p.first;
            auto v = p.second;
            if (d[v] < dist) continue;
            REP(i, m_G[v].size()) {
                edge e = m_G[v][i];
                if (d[e.to] > d[v] + e.cost) {
                    d[e.to] = d[v] + e.cost;
                    que.push(P(d[e.to], e.to));
                    m_prev_path[e.to] = v;
                }
            }
        }

        return d;
    }

    // shortest_path()が呼ばれた後に呼ばれることを期待する
    // s -> v1 -> v2 -> v3 -> t の場合、{s, v1, v2, v3, t} からなるvectorを返す
    vector<int> get_path(int t)
    {
        vector<int> path;
        for(; t != -1; t = m_prev_path[t]) path.push_back(t);
        reverse(ALL(path));
        return path;
    }

};

vector<int> solve(const int N, const vector<pair<int, int>>& ABs) {
    vector<int> ans(N + 1);

    vector<vector<int>> edges(N + 1);
    Dijkstra<int> dij(N);
    for(auto ab: ABs) {
        auto a = ab.first;
        auto b = ab.second;
        edges[a].pb(b);
        edges[b].pb(a);
        dij.add_undir_edge(a - 1, b - 1, 1);
    }

    // 直径を求める
    auto ret = dij.shortest_path(0);
    int far_v = 0;
    int far_d = 0;
    REP(n, N) {
        if (ret[n] > far_d) {
            far_v = n;
            far_d = ret[n];
        }
    }
    auto ret2 = dij.shortest_path(far_v);
    int diameter = 0;
    REP(n, N) {
        if (ret2[n] > diameter) {
            diameter = ret2[n];
        }
    }

    // 直径2以下なら任意の数列でOK
    if (diameter <= 2) {
        REP(n, N + 1) {
            ans[n] = n;
        }
        return ans;
    }

    vector<int> nodes;
    nodes.pb(1);
    vector<int> ones;
    vector<int> twos;

    vector<int> seen(N + 1);
    bool one_flag = true;
    seen[1] = 1;
    while(!nodes.empty()) {
        vector<int> next_nodes;
        for(auto node: nodes) {
            if (one_flag) {
                ones.pb(node);
            } else {
                twos.pb(node);
            }
            for(auto nei: edges[node]) {
                if (!seen[nei]) {
                    next_nodes.pb(nei);
                    seen[nei] = true;
                }
            }
        }
        one_flag = !one_flag;
        nodes = next_nodes;
    }

    //cout << "ones:";
    //for(auto o: ones) cout << o << " ";
    //cout << endl;
    //cout << "twos:";
    //for(auto t: twos) cout << t << " ";
    //cout << endl;

    int mod0 = 0;
    int mod1 = 0;
    int mod2 = 0;
    FOR(i, 1, N + 1) {
        if (i % 3 == 0) ++mod0;
        else if (i % 3 == 1) ++mod1;
        else ++mod2;
    }

    if (SIZE(twos) > SIZE(ones)) {
        swap(ones, twos);
    }


    if (SIZE(ones) < mod1) {
        return vector<int>{-1};
    }
    if (SIZE(twos) < mod2) {
        return vector<int>{-1};
    }

    vector<int> zeros;
    while(SIZE(ones) > mod1) {
        zeros.pb(ones.back());
        ones.pop_back();
    }
    while(SIZE(twos) > mod2) {
        zeros.pb(twos.back());
        twos.pop_back();
    }

    //cout << endl;
    //cout << "zeros:";
    //for(auto z: zeros) cout << z << " ";
    //cout << endl;
    //cout << "ones:";
    //for(auto o: ones) cout << o << " ";
    //cout << endl;
    //cout << "twos:";
    //for(auto t: twos) cout << t << " ";
    //cout << endl;


    int i = 3;
    for(auto z: zeros) {
        ans[z] = i;
        i += 3;
    }
    i = 1;
    for(auto o: ones) {
        ans[o] = i;
        i += 3;
    }
    i = 2;
    for(auto t: twos) {
        ans[t] = i;
        i += 3;
    }
    return ans;
}

int main(void)
{
     //// for debug
     //{
     //    while(1) {
     //        int N = rand() % 6 + 2;
     //        vector<pair<int, int>> ABs;
     //        Dijkstra<int> dij(N);
     //        FOR(n, 2, N + 1) {
     //            int v = (rand() % (n - 1)) + 1;
     //            ABs.pb(mp(n, v));
     //            cout << "edge: " << n << " " << v << endl;
     //            dij.add_undir_edge(n - 1, v - 1, 1);
     //        }
     //        auto ans = solve(N, ABs);

     //        // 検算
     //        cout << "ans: ";
     //        FOR(i, 1, N + 1) {
     //            cout << " " << ans[i];
     //        }
     //        cout << endl;

     //        REP(a, N) {
     //            auto dist = dij.shortest_path(a);
     //            REP(b, N) {
     //                if (a == b) continue;
     //                if (dist[b] == 3) {
     //                    int val1 = ans[a + 1];
     //                    int val2 = ans[b + 1];
     //                    if ((val1 + val2) % 3 == 0 || (val1 * val2) % 3 == 0) continue;

     //                    cout << "error!" << endl;
     //                    cout << "v" << (a + 1) << " and v" << (b + 1) << " fail" << endl;
     //                    return 0;
     //                }
     //            }
     //        }

     //        cout << endl;
     //    }
     //}

    cin.sync_with_stdio(false);
    int N;
    cin >> N;
    vector<pair<int, int>> ABs(N-1);

    REP(n, N - 1) {
        int a, b;
        cin >> a >> b;
        ABs[n] = mp(a, b);
    }

    auto ans = solve(N, ABs);
    FOR(i, 1, N + 1) {
        if (i != 1) cout << " ";
        cout << ans[i];
    }
    cout << endl;
    
    return 0;
}