#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
#include <numeric>
#include <tuple>
#include <cassert>

template <class T, class U>
inline bool chmin(T& lhs, const U& rhs) {
  if (lhs > rhs) {
    lhs = rhs;
    return true;
  }
  return false;
}

template <class T, class U>
inline bool chmax(T& lhs, const U& rhs) {
  if (lhs < rhs) {
    lhs = rhs;
    return true;
  }
  return false;
}

// [l, r) from l to r
struct range {
  struct itr {
    int i;
    constexpr itr(int i_): i(i_) { }
    constexpr void operator ++ () { ++i; }
    constexpr int operator * () const { return i; }
    constexpr bool operator != (itr x) const { return i != x.i; }
  };
  const itr l, r;
  constexpr range(int l_, int r_): l(l_), r(std::max(l_, r_)) { }
  constexpr itr begin() const { return l; }
  constexpr itr end() const { return r; }
};

// [l, r) from r to l
struct revrange {
  struct itr {
    int i;
    constexpr itr(int i_): i(i_) { }
    constexpr void operator ++ () { --i; }
    constexpr int operator * () const { return i; }
    constexpr bool operator != (itr x) const { return i != x.i; }
  };
  const itr r, l;
  constexpr revrange(int l_, int r_): l(l_ - 1), r(std::max(l_, r_) - 1) { }
  constexpr itr begin() const { return r; }
  constexpr itr end() const { return l; }
};

int N;
int col[200000];
int used[200001];
int ans[200000];
std::vector<int> graph[200000];

void dfs(int u, int p, int c) {
  col[u] = c;
  for (int v: graph[u]) {
    if (v != p) {
      dfs(v, u, 3 - c);
    }
  }
}

int main() {
  std::cin >> N;
  for (int i: range(0, N - 1)) {
    int a, b;
    std::cin >> a >> b;
    --a; --b;
    graph[a].push_back(b);
    graph[b].push_back(a);
  }
  dfs(0, -1, 1);
  int one = std::count(col, col + N, 1);
  int two = std::count(col, col + N, 2);
  int three = N / 3;
  if (one < two) {
    std::swap(one, two);
    for (int i: range(0, N)) {
      if (col[i] == 1) col[i] = 2;
      else if (col[i] == 2) col[i] = 1;
    }
  }
  // one >= two
  if (one - two > three) {
    int now = 3;
    for (int i: range(0, N)) {
      if (col[i] == 2) {
        ans[i] = now;
        used[now] = true;
        now += 3;
      }
    }
    std::vector<int> vec;
    for (int i: range(1, N + 1)) {
      if (!used[i]) {
        vec.push_back(i);
      }
    }
    for (int i: range(0, N)) {
      if (ans[i] == 0) {
        ans[i] = vec.back();
        vec.pop_back();
      }
    }
  }
  else {
    int now = 3;
    for (int i: range(0, N)) {
      if (col[i] == 1 && one > (N + 2) / 3) {
        ans[i] = now;
        used[now] = true;
        now += 3;
        --one;
      }
    }
    for (int i: range(0, N)) {
      if (col[i] == 2 && two > (N + 1) / 3) {
        ans[i] = now;
        used[now] = true;
        now += 3;
        --two;
      }
    }
    three = N - one - two;
    for (int i: range(0, N)) {
      if (ans[i] == 0 && three < N / 3) {
        ans[i] = now;
        used[now] = true;
        now += 3;
        ++three;
      }
    }
    assert(three == N / 3 && one == (N + 2) / 3 && two == (N + 1) / 3);
    std::vector<int> vec[3];
    for (int i: range(1, N + 1)) {
      if (!used[i]) {
        vec[i % 3].push_back(i);
      }
    }
    for (int i: range(0, N)) {
      if (ans[i] == 0) {
        ans[i] = vec[col[i]].back();
        vec[col[i]].pop_back();
      }
    }
  }
  for (int i: range(0, N)) {
    std::cout << ans[i] << (i + 1 < N ? ' ' : '\n');
  }
  return 0;
}


Measured memory_bytes: 20076