Problem:
Height of a Tree
Given a tree
T
with non-negative weight, find the height of each node of the tree. For each node, the height is the distance to the most distant leaf from the node.
Input
n
s
1
t
1
w
1
s
2
t
2
w
2
:
s
n-1
t
n-1
w
n-1
The first line consists of an integer
n
which represents the number of nodes in the tree. Every node has a unique ID from 0 to
n
-1 respectively.
In the following
n
-1 lines, edges of the tree are given.
s
i
and
t
i
represent end-points of the
i
-th edge (undirected) and
w
i
represents the weight (distance) of the
i
-th edge.
Output
The output consists of
n
lines. Print the height of each node 0, 1, 2, ...,
n-1
in order.
Constraints
1 ≤
n
≤ 10,000
0 ≤
w
i
≤ 1,000
Sample Input 1
4
0 1 2
1 2 1
1 3 3
Sample Output 1
5
3
4
5

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <cstring>

#define MAXN 10000

using namespace std;

struct edge{
	int nn;
	int w;
	edge(int a, int b){nn = a; w = b;}
};

vector<edge> node[MAXN];

int maxdist[MAXN];
int visited[MAXN];

void DFS(int idx, int w){
	visited[idx] = 1;
	if(w > maxdist[idx]) maxdist[idx] = w;
	
	for(int i = 0; i < node[idx].size(); i++){
		if(visited[node[idx][i].nn]) continue;
		
		DFS(node[idx][i].nn, w + node[idx][i].w);
	}
}

int main(){
	
	int n;
	int x, y, z;
	
	cin >> n;
	
	for(int i = 0; i < n - 1; i++){
		cin >> x >> y >> z;
		
		node[x].push_back(edge(y,z));
		node[y].push_back(edge(x,z));
	}
	
	for(int i = 0; i < n; i++){
		if(node[i].size() != 1) continue;
		memset(visited, 0, sizeof(visited));
		DFS(i, 0);
	}
	
	for(int i = 0; i < n; i++) cout << maxdist[i] << endl;
	
	return 0;
}
accuracy: 1
time_ms: 780
memory_kb: 4288
final_rank: 20

code_snippet: #include <bits/stdc++.h>
#define INF 0x7fffffff
#define MAXN 200010
typedef long long LL;
using namespace std;

struct node
{
	int v, w;	
};

int n, m;
vector <node> g[MAXN];
int dp[MAXN], ans[MAXN];

void treeDepth(int u, int parent)
{
	dp[u] = 0;
	for(int x = 0; x < g[u].size(); x++)
	{
		int v = g[u][x].v, w = g[u][x].w;
		if(v == parent) continue;
		treeDepth(v, u);
		dp[u] = max(dp[u], dp[v] + w);
	}
}

void changeRoot(int u, int parent, int up)
{
	vector <int> pre, suf;
	for(int x = 0; x < g[u].size(); x++)
	{
		int v = g[u][x].v, w = g[u][x].w;
		if(v == parent) pre.push_back(up);
		else pre.push_back(dp[v] + w);
	}
	suf = pre;
	for(int x = 1; x < g[u].size(); x++) pre[x] = max(pre[x], pre[x-1]);
	for(int x = g[u].size() - 2; x >= 0; x--) suf[x] = max(suf[x], suf[x+1]);
	ans[u] = max(dp[u], up);
	for(int x = 0; x < g[u].size(); x++)
	{
		int v = g[u][x].v, w = g[u][x].w;
		if(v == parent) continue;
		int left = (x == 0 ? -INF : pre[x-1]);
		int right = (x == g[u].size()-1 ? -INF : suf[x+1]);
		int newUp = max(up, max(left, right)) + w;
		changeRoot(v, u, newUp);
	}
}

void treeHeight()
{
	treeDepth(0, -1);
	changeRoot(0, -1, 0);
}

int main()
{
	cin >> n;
	m = n - 1;
	for(int x = 1; x <= m; x++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		g[u].push_back((node){v, w});
		g[v].push_back((node){u, w});
	}
	treeHeight();
	for(int x = 0; x < n; x++) cout << ans[x] << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 10568
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<ll, ll> P;

struct Edge {
    ll to, cost;
};

const ll INF = 8e18;
vector<ll> dijkstra(ll n, vector<vector<Edge>>& graph, ll start) {
    vector<ll> dist(n,INF);
    priority_queue<P, vector<P>, greater<P>> que;
    dist[start] = 0;
    que.push({0,start});

    while (!que.empty()) {
        ll current_dist = que.top().first;
        ll pos = que.top().second;
        que.pop();

        if (current_dist > dist[pos]) continue;

        for (auto edge : graph[pos]) {
            ll nex = edge.to;
            ll cost = edge.cost;

            if (dist[nex] > dist[pos]+cost) {
                dist[nex] = dist[pos] + cost;
                que.push({dist[nex], nex});
            }
        }
    }
        return dist;
}

int main() {
    ll n; cin >> n;
    vector<vector<Edge>> graph(n);
    for (ll i = 0; i < n-1; i++) {
        ll a, b, w;
        cin >> a >> b >> w;
        graph[a].push_back({b,w});
        graph[b].push_back({a,w});
    }

        vector<ll> a = dijkstra(n, graph, 0);
        ll num1 = 0;
        ll A_index = 0;
        for (int i = 0; i < n; i++) {
                if (num1 < a[i]) {
                        num1 = a[i];
                        A_index = i;
                }
        }

        vector<ll> b = dijkstra(n, graph, A_index);
        ll num2 = 0;
        ll B_index = 0;
        for (int i = 0; i < n; i++) {
                if (num2 < b[i]) {
                        num2 = b[i];
                        B_index = i;
                }
        }

        vector<ll> distA = b;
        vector<ll> distB = dijkstra(n, graph, B_index);

        for (int i = 0; i < n; i++) {
                ll ans = max(distA[i], distB[i]);
                cout << ans << endl;
        }
        return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4504
final_rank: 9

code_snippet: // aizu_GRL_5_B_HeightTree_a.cc
// 

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define rep(i,n) for (int i=0;i<(n);i++)

void bfs(int s, vector<vector<pair<int,int>>> &graph,vector<int> &height){
  queue<pair<int,int>> que;
  que.push(make_pair(s,-1));
  while ( que.size()!= 0){
    auto q = que.front();
    que.pop();
    int now =q.first;
    int par = q.second;
    for ( auto t : graph[now]){
      if (t.first == par )continue;
      height[t.first] =height[now] +t.second;
      que.push(make_pair(t.first,now));
    }
  }
}

int main(){
  int n;
  cin >> n;
  vector<vector<pair<int,int>>> graph(n);

  rep(i,n-1) {
    int s,t,w;
    cin >> s >> t >> w;
    graph[s].emplace_back(t,w);
    graph[t].emplace_back(s,w);
  }
  vector<int>height0(n),height1(n);
  bfs(0,graph,height0);
  auto iterator = max_element(height0.begin(), height0.end());
  int index0 = distance(height0.begin(), iterator);

  rep(i,n) height0[i] =  0;
  bfs(index0,graph,height0);  
  auto iterator1 = max_element(height0.begin(), height0.end());
  int index1 = distance(height0.begin(), iterator1);

  bfs(index1,graph,height1);  
  rep(i,n){
    cout << max(height0[i], height1[i]) << endl;
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3964
final_rank: 1

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <queue>
using namespace std;
typedef long long ll;
// const ll INF64 = 1LL << 60;
const ll INF64 = ((1LL<<62)-(1LL<<31));  // 10^18より大きく、かつ2倍しても負にならない数
const int INF32 = 0x3FFFFFFF;  // =(2^30)-1 10^9より大きく、かつ2倍しても負にならない数
template<class T> inline bool chmin(T &a, T b) { if(a > b) { a = b; return true; } return false; }
template<class T> inline bool chmax(T &a, T b) { if(a < b) { a = b; return true; } return false; }
#define YesNo(T) cout << ((T) ? "Yes" : "No") << endl;  // T:bool

// https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_5_B

/*
 * 木の直径をs-tとすると、
 * 各頂点iについて i-s もしくは i-t が最も遠い点となる。
 */

// 頂点を結ぶ辺
struct Edge
{
	int to;  // 隣接頂点番号
	ll weight;  // 辺の重み
	Edge(int to_, ll weight_) : to(to_), weight(weight_) {}
};
using Graph = vector<vector<Edge>>;

// 頂点sから最も遠い頂点を返す BFS使用
int mostfar(Graph &G, int s, vector<int> &dist)
{
	queue<int> que;
	dist[s] = 0;
	que.push(s);

	while(!que.empty())
	{
		int v = que.front();
		que.pop();
		for(auto &e : G[v])
		{
			if(dist[e.to] != INF32) continue;
			dist[e.to] = dist[v] + e.weight;
			que.push(e.to);
		}
	}
	int idx = max_element(dist.begin(), dist.end()) - dist.begin();
	return idx;
}

int main(void)
{
	int i;
	int N; cin >> N;
	Graph g(N);
	for(i = 0; i < N-1; i++)
	{
		int s, t, w; cin >> s >> t >> w;
		g[s].push_back({t, w});
		g[t].push_back({s, w});
	}
	vector<int> dist_0(N, INF32), dist_s(N, INF32), dist_t(N, INF32);
	int s = mostfar(g, 0, dist_0);
	int t = mostfar(g, s, dist_s);
	mostfar(g, t, dist_t);
	for(i = 0; i < N; i++)
	{
		cout << max(dist_s[i], dist_t[i]) << endl;
	}

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4188
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <queue>
using namespace std;
typedef long long ll;
// const ll INF64 = 1LL << 60;
const ll INF64 = ((1LL<<62)-(1LL<<31));  // 10^18より大きく、かつ2倍しても負にならない数
const int INF32 = 0x3FFFFFFF;  // =(2^30)-1 10^9より大きく、かつ2倍しても負にならない数
template<class T> inline bool chmin(T &a, T b) { if(a > b) { a = b; return true; } return false; }
template<class T> inline bool chmax(T &a, T b) { if(a < b) { a = b; return true; } return false; }
#define YesNo(T) cout << ((T) ? "Yes" : "No") << endl;  // T:bool

// https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_5_B

/*
 * 
 * 
 * 
 */

// 頂点を結ぶ辺
struct Edge
{
	int to;  // 隣接頂点番号
	ll weight;  // 辺の重み
	Edge(int to_, ll weight_) : to(to_), weight(weight_) {}
};
using Graph = vector<vector<Edge>>;

// 頂点sから最も遠い頂点を返す BFS使用
int mostfar(Graph &G, int s, vector<int> &dist)
{
	queue<int> que;
	dist[s] = 0;
	que.push(s);

	while(!que.empty())
	{
		int v = que.front();
		que.pop();
		for(auto &e : G[v])
		{
			if(dist[e.to] != INF32) continue;
			dist[e.to] = dist[v] + e.weight;
			que.push(e.to);
		}
	}
	int idx = max_element(dist.begin(), dist.end()) - dist.begin();
	/*
	int idx = -1, mx = -1;
	for(int i = 0; i < (int)dist.size(); i++)
	{
		if(chmax(mx, dist[i])) idx = i;
	}
	*/
	return idx;
}

int main(void)
{
	int i;
	int N; cin >> N;
	Graph g(N);
	for(i = 0; i < N-1; i++)
	{
		int s, t, w; cin >> s >> t >> w;
		g[s].push_back({t, w});
		g[t].push_back({s, w});
	}
	vector<int> dist_0(N, INF32), dist_s(N, INF32), dist_t(N, INF32);
	int s = mostfar(g, 0, dist_0);
	int t = mostfar(g, s, dist_s);
	mostfar(g, t, dist_t);
	for(i = 0; i < N; i++)
	{
		cout << max(dist_s[i], dist_t[i]) << endl;
	}

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4132
final_rank: 3

code_snippet: #include<bits/stdc++.h>
using namespace std;
int main(){
    int N;cin>>N;
    vector<vector<pair<int,int>>>E(N);
    for(int i=0;i<N-1;i++){
        int s,t,w;cin>>s>>t>>w;
        E[s].emplace_back(make_pair(t,w));
        E[t].emplace_back(make_pair(s,w));
    }
    vector<int>D(N,1000000000);
    D[0]=0;
    function<void(int)>dfs=[&](int v){
        for(auto[u,w]:E[v])if(D[u]>D[v]+w){
            D[u]=D[v]+w;
            dfs(u);
        }
    };
    dfs(0);
    int a=max_element(D.begin(),D.end())-D.begin();
    fill(D.begin(),D.end(),1000000000);
    D[a]=0;
    dfs(a);
    auto D0=D;
    int b=max_element(D.begin(),D.end())-D.begin();
    fill(D.begin(),D.end(),1000000000);
    D[b]=0;
    dfs(b);
    for(int i=0;i<N;i++)cout<<max(D[i],D0[i])<<endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4444
final_rank: 8

code_snippet: #line 1 "verify/AOJ-GRL-5-B.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/5/GRL/5/GRL_5_B"

#line 2 "Library/Template.hpp"

/**
 * @file Template.hpp
 * @author log K (lX57)
 * @brief Template - テンプレート
 * @version 1.8
 * @date 2024-06-16
 */

#line 2 "Library/Common.hpp"

/**
 * @file Common.hpp
 */

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;
#line 12 "Library/Template.hpp"
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define SORT(x) sort(ALL(x))
#define RSORT(x) sort(RALL(x))
#define REVERSE(x) reverse(ALL(x))
#define SETPRE(digit) fixed << setprecision(digit)
#define POPCOUNT(x) __builtin_popcount(x)
#define SUM(x) reduce((x).begin(), (x).end())
#define CEIL(nume, deno) ((nume) + (deno) - 1) / (deno)
#define IOTA(x) iota((x).begin(), (x).end(), 0)
#define LOWERBOUND_IDX(arr, val) distance((arr).begin(), lower_bound((arr).begin(), (arr).end(), val))
#define UPPERBOUND_IDX(arr, val) distance((arr).begin(), upper_bound((arr).begin(), (arr).end(), val))

inline string Yn(bool flag){return (flag) ? "Yes" : "No";}
inline bool YnPrint(bool flag){cout << Yn(flag) << endl;return flag;}
inline string YN(bool flag){return (flag) ? "YES" : "NO";}
inline bool YNPrint(bool flag){cout << YN(flag) << endl;return flag;}
template<class T>
bool chmin(T &src, const T &cmp){if(src > cmp){src = cmp; return true;}return false;}
template<class T>
bool chmax(T &src, const T &cmp){if(src < cmp){src = cmp; return true;}return false;}
template<typename T>
inline bool between(T min, T x, T max){return min <= x && x <= max;}
template<typename T>
inline bool ingrid(T y, T x, T ymax, T xmax){return between(0, y, ymax - 1) && between(0, x, xmax - 1);}
template<typename T>
inline T median(T a, T b, T c){return between(b, a, c) || between(c, a, b) ? a : (between(a, b, c) || between(c, b, a) ? b : c);}
template<typename T>
inline T except(T src, T cond, T excp){return (src == cond ? excp : src);}
template<typename T>
inline T min(vector<T> &v){return *min_element((v).begin(), (v).end());}
template<typename T>
inline T max(vector<T> &v){return *max_element((v).begin(), (v).end());}
vector<int> make_sequence(int Size){
    vector<int> ret(Size);
    IOTA(ret);
    return ret;
}
template<typename T>
void make_unique(vector<T> &v){
    sort(v.begin(), v.end());
    auto itr = unique(v.begin(), v.end());
    v.erase(itr, v.end());
}

using ll = int64_t;
using ull = uint64_t;
using ld = long double;

const int INF_INT = numeric_limits<int>::max() >> 2;
const ll INF_LL = numeric_limits<ll>::max() >> 2;

using vi = vector<int>;
using vvi = vector<vi>;
using vl = vector<ll>;
using vvl = vector<vl>;
using pi = pair<int, int>;
using pl = pair<ll, ll>;
using vs = vector<string>;
template <typename T>
using pq = priority_queue<T>;
template <typename T>
using rpq = priority_queue<T, vector<T>, greater<T>>;

const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};

vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
    vector<pair<int, int>> ret;
    for(int d = 0; d < 4 * (1 + dir_8); ++d){
        int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
        int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
        if(0 <= next_y and next_y < max_y and 0 <= next_x and next_x < max_x){
            ret.emplace_back(next_y, next_x);
        }
    }
    return ret;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
    os << p.first << " " << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? "\n" : "");
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, set<T> &v){
    for (auto &u : v){
        os << u << " ";
    }
    return os;
}

template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
    assert(v1.size() == v2.size());
    vector<pair<T1, T2>> v;
    for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
    return v;
}

template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
    vector<T1> v1;
    vector<T2> v2;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
    return {v1, v2};
}

template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
    transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
    return {v1, v2, v3};
}

template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
    vector<pair<T1, T2>> v(size);
    for(auto &[p, q] : v) cin >> p >> q;
    return DisassembleVectorPair(v);
}

template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
    vector<tuple<T1, T2, T3>> v(size);
    for(auto &[p, q, r] : v) cin >> p >> q >> r;
    return DisassembleVectorTuple(v);
}

#ifdef LOGK
#define DEBUG(fmt, ...) fprintf(stderr, fmt __VA_OPT__(,) __VA_ARGS__)
#define VARIABLE(var) cerr << "# " << #var << " = " << var << endl;
#else
#define DEBUG(...) 42
#define VARIABLE(...) 42
#endif

// ==============================================================
// 
// Main Program Start
// 
// ==============================================================
#line 1 "Library/Tree/RerootingDP.hpp"
/**
 * @file RerootingDP.hpp
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-09-03
 * 
 * @copyright Copyright (c) 2024
 * 
 */

#line 2 "Library/Tree/Tree.hpp"

/**
 * @file Tree.hpp
 * @brief Tree - 木テンプレート
 * @version 0.1
 * @date 2024-07-29
 */

#line 11 "Library/Tree/Tree.hpp"

using Vertex = int;

template<typename CostType = int32_t>
class RootedTree{
    public:
    struct Node{
        Node(Vertex parent = -1) : parent(parent){}

        Vertex parent{-1};
        CostType cost{};
        vector<Vertex> children{};
    };

    /**
     * @brief 頂点 `root_vertex` を根とする頂点数 `vertex_size` の根付き木を構築する。
     * @note 根が入力で与えられなれないが後で分かる、みたいな状況の時は `root_vertex = -1` とするとよい
     * @param vertex_size 頂点数
     * @param root_vertex 根とする頂点 (default = 0)
     */
    RootedTree(int vertex_size, Vertex root_vertex = 0) :
            vertex_size_(vertex_size), root_vertex_(root_vertex),
            node_(vertex_size){}

    /**
     * @brief 木の頂点数を返す。
     * @return int 木の頂点数
     */
    int get_vertex_size() const {
        return vertex_size_;
    }

    /**
     * @brief 木の根の頂点を返す。
     * @return Vertex 木の根の頂点番号 (0-index)
     */
    Vertex get_root() const {
        return root_vertex_;
    }

    /**
     * @brief 頂点 `v` の親の頂点番号を返す。
     * @note `v` が根の場合、`-1` が返される。
     * @param v 子の頂点番号 (0-index)
     * @return Vertex 親の頂点番号 (0-index)
     */
    Vertex get_parent(Vertex v) const {
        Validate(v);
        return node_[v].parent;
    }

    /**
     * @brief 頂点 `v` の子の頂点番号列を返す。
     * @note 頂点番号列は入力順に返される。
     * @param v 親の頂点番号 (0-index)
     * @return vector<Vertex> 子の頂点番号列 (0-index)
     */
    vector<Vertex> &get_child(Vertex v){
        Validate(v);
        return node_[v].children;
    }

    /**
     * @brief 頂点 `v` とその親を結ぶ辺の重みを返す。
     * @attention `v` が根の場合の返り値は未定義である。
     * @param v 頂点番号 (0-index)
     * @return CostType 辺の重み
     */
    CostType get_cost(Vertex v){
        Validate(v);
        return node_[v].cost;
    }

    /**
     * @brief 頂点 `parent` から頂点 `child` への重さ `cost` の辺を張る。
     * @note `cost` を省略することで重みなし辺を張ることができる。
     * @param parent 親の頂点番号 (0-index)
     * @param child 子の頂点番号 (0-index)
     * @param cost 辺の重み (default = 1)
     */
    void AddEdge(Vertex parent, Vertex child, CostType cost = 1){
        Validate(parent);
        Validate(child);
        node_[parent].children.push_back(child);
        node_[child].parent = parent;
        node_[child].cost = cost;
    }

    /**
     * @brief `u v w` のような入力形式を受け取る。
     * @param weighted 重み付きの木であるか (default = true)
     * @param one_index 入力される頂点番号が 1-index かどうか (default = true)
     */
    void InputGraphFormat(bool weighted = true, bool one_index = true){
        vector<vector<pair<Vertex, CostType>>> graph(vertex_size_);
        for(int i = 0; i < vertex_size_ - 1; ++i){
            int u, v; cin >> u >> v;
            if(one_index) --u, --v;
            CostType w = 1;
            if(weighted) cin >> w;
            graph[u].emplace_back(v, w);
            graph[v].emplace_back(u, w);
        }
        auto rec = [&](auto self, Vertex v, Vertex p) -> void {
            for(auto [u, w] : graph[v]){
                if(u == p) continue;
                AddEdge(v, u, w);
                self(self, u, v);
            }
        };
        rec(rec, root_vertex_, -1);
    }

    /**
     * @brief `p_1 p_2 ... p_N` のような入力形式を受け取る。
     * @attention weighted の処理を書いていないので、`weighted` のパラメータに意味はない
     * @param weighted 重み付きの木であるか (default = true)
     * @param one_index 入力される頂点番号が 1-index かどうか (default = true)
     */
    void InputRootedTreeFormat(bool weighted = true, bool one_index = true){
        assert(root_vertex_ == 0);
        for(int i = 1; i < vertex_size_; ++i){
            int p; cin >> p;
            if(one_index) --p;
            AddEdge(p, i);
        }
    }

    /**
     * @brief 頂点 `v` が根の頂点か判定する。
     * @param v 判定する頂点番号 (0-index)
     */
    bool RootVertex(Vertex v){
        Validate(v);
        return node_[v].parent == -1;
    }
    
    /**
     * @brief 頂点 `v` が葉の頂点か判定する。
     * @param v 判定する頂点番号 (0-index)
     */
    bool LeafVertex(Vertex v){
        Validate(v);
        return node_[v].children.empty();
    }

    /**
     * @brief 木の根の頂点を求める。
     * @attention 基本的には不要で、根の頂点番号が与えられていない場合に用いる。
     * @note Verify : https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/7/ALDS1_7_A
     * @return Vertex 根の頂点番号
     */
    Vertex FindRoot(){
        for(int i = 0; i < vertex_size_; ++i){
            if(RootVertex(i)){
                root_vertex_ = i;
                return i;
            }
        }
        assert(false);
    }

    /**
     * @brief 木の根を変更して再構築する。
     * @param root 新しい根の頂点番号 (0-index)
     */
    void Rerooting(Vertex root){
        if(root == root_vertex_) return;
        vector<Node> new_node_(vertex_size_);
        auto rec = [&](auto self, Vertex v, Vertex p, CostType c) -> void {
            new_node_[v].parent = p;
            new_node_[v].cost = c;
            if(node_[v].parent != p && node_[v].parent != -1){
                new_node_[v].children.push_back(node_[v].parent);
                self(self, node_[v].parent, v, node_[v].cost);
            }
            for(Vertex u : node_[v].children){
                if(u != p){
                    new_node_[v].children.push_back(u);
                    self(self, u, v, node_[u].cost);
                }
            }
        };
        rec(rec, root, -1, 0);
        swap(new_node_, node_);
        root_vertex_ = root;
    }

    void Print(bool one_index = true) const {
        for(int i = 0; i < vertex_size_; ++i){
            // fprintf(stderr, "# Vertex %d : parent = %d (cost = %d), children = [", i + int(one_index), get_parent(i) + int(one_index), node_[i].cost);
            fprintf(stderr, "# Vertex %d : parent = %d (cost = ", i + int(one_index), get_parent(i) + int(one_index));
            cerr << node_[i].cost;
            fprintf(stderr, "), children = [");
            for(int j = 0; j < node_[i].children.size(); ++j){
                fprintf(stderr, "%d", node_[i].children[j]);
                if(j + 1 < node_[i].children.size()){
                    fprintf(stderr, ", ");
                }
            }
            fprintf(stderr, "]\n");
        }
    }

    private:
    inline void Validate(Vertex v) const {
        assert(0 <= v && v < vertex_size_);
    }

    int vertex_size_, root_vertex_{-1};
    vector<Node> node_;
};

/**
 * @brief 木 `tree` の各頂点の深さを求める。
 * @note 根の頂点は深さ 0 である。
 * @note Verify : https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/7/ALDS1_7_A
 * @param tree 木
 * @param root 根の頂点番号 (default = 0)
 * @return vector<int> 各頂点の深さ
 */
template<typename CostType>
vector<int> CalculateTreeDepth(RootedTree<CostType> &tree){
    int V = tree.get_vertex_size();
    vector<int> ret(V, 0);
    auto rec = [&](auto self, Vertex v, int d) -> void {
        ret[v] = d;
        for(Vertex u : tree.get_child(v)){
            self(self, u, d + 1);
        }
    };
    Vertex root = tree.get_root();
    if(root < 0) root = tree.FindRoot();
    rec(rec, root, 0);
    return ret;
}

/**
 * @brief 木の根から各頂点への辺の重みの累積和を計算する。
 * @param tree 木
 * @return vector<CostType> 根から各頂点への重みの累積和
 */
template<typename CostType>
vector<CostType> CalculateTreeCumlativeSum(RootedTree<CostType> &tree){
    Vertex root = tree.get_root();
    int V = tree.get_vertex_size();
    vector<CostType> ret(V, 0);
    auto rec = [&](auto self, Vertex v, CostType s) -> void {
        ret[v] = s + tree.get_cost(v);
        for(Vertex u : tree.get_child(v)){
            self(self, u, ret[v]);
        }
    };
    rec(rec, root, 0);
    return ret;
}
#line 13 "Library/Tree/RerootingDP.hpp"

template<typename CostType, typename Monoid>
class RerootingDP{
    public:
    using F = function<Monoid(Monoid, Monoid, Vertex)>;
    using G = function<Monoid(Monoid, CostType, Vertex)>;
    using H = function<Monoid(Monoid, Vertex)>;
    using Fsub = function<Monoid(Monoid, Monoid)>;
    using Gsub = function<Monoid(Monoid, CostType)>;

    /**
     * @brief 木 `tree` に対して全方位木DPを行う。(辺属性のみ)
     * @param tree 根付き木
     * @param merge `(Monoid, Monoid) -> Monoid` : `Monoid` 同士に関する二項演算。
     * @param add `(Monoid, CostType) -> Monoid` : `Monoid` と `CostType` に関する二項演算。
     * @param monoid_identity `Monoid` の単位元。
     */
    RerootingDP(RootedTree<CostType> &tree, Fsub merge, Gsub add, const Monoid monoid_identity) :
            tree_(tree), V(tree.get_vertex_size()), merge_sub_(merge), add_sub_(add), id_(monoid_identity){
        merge_ = [&](Monoid x, Monoid y, Vertex i){return merge_sub_(x, y);};
        add_ = [&](Monoid x, CostType y, Vertex i){return add_sub_(x, y);};
        finalize_ = [](Monoid x, Vertex i){return x;};
        solve();
    }

    /**
     * @brief 木 `tree` に対して全方位木DPを行う。(頂点属性を含む)
     * @param tree 根付き木
     * @param merge `(Monoid, Monoid, Vertex) -> Monoid` : `Monoid` 同士に関する二項演算。
     * @param add `(Monoid, CostType, Vertex) -> Monoid` : `Monoid` と `CostType` に関する二項演算。
     * @param finalize `(Monoid, Vertex) -> Monoid` : `Monoid` に頂点 `Vertex` が根のときの処理。
     * @param monoid_identity `Monoid` の単位元。
     */
    RerootingDP(RootedTree<CostType> &tree, F merge, G add, H finalize, const Monoid monoid_identity) :
            tree_(tree), V(tree.get_vertex_size()), merge_(merge), add_(add), finalize_(finalize), id_(monoid_identity){
        solve();
    }

    /**
     * @brief 全頂点に関するDPの配列を取得する。
     */
    vector<Monoid> &get_all_answer(){
        return dp_;
    }

    Monoid operator[](Vertex v){
        return dp_[v];
    }

    const Monoid operator[](Vertex v) const {
        return dp_[v];
    }

    void Print() const {
        cerr << "# dp table :";
        for(int i = 0; i < V; ++i){
            cerr << " " << dp_[i];
        }
        cerr << endl;
        cerr << "# subtree_dp table" << endl;
        for(int i = 0; i < V; ++i){
            cerr << "# vertex " << i << endl;
            cerr << "#    subtree_dp :";
            for(int j = 0; j < subtree_dp_[i].size(); ++j){
                cerr << " " << subtree_dp_[i][j];
            }
            cerr << endl;
            cerr << "#    left_cum   :";
            for(int j = 0; j < left_cum_[i].size(); ++j){
                cerr << " " << left_cum_[i][j];
            }
            cerr << endl;
            cerr << "#    right_cum  :";
            for(int j = 0; j < right_cum_[i].size(); ++j){
                cerr << " " << right_cum_[i][j];
            }
            cerr << endl;
        }
    }

    private:
    RootedTree<CostType> &tree_;

    Monoid dfs(Vertex v, bool root = false){
        Monoid ret = id_;
        for(auto u : tree_.get_child(v)){
            Monoid res = dfs(u);
            subtree_dp_[v].push_back(res);
            ret = merge_(ret, res, v);
        }
        if(root) ret = finalize_(ret, v);
        else ret = add_(ret, tree_.get_cost(v), v);
        return ret;
    }

    void solve(){
        dp_.resize(V, id_);
        subtree_dp_.resize(V, vector<Monoid>{id_});
        left_cum_.resize(V);
        right_cum_.resize(V);
        Vertex root = tree_.get_root();

        dp_[root] = dfs(root, true);
        int root_size = subtree_dp_[root].size();
        left_cum_[root].resize(root_size + 1);
        left_cum_[root].front() = id_;
        for(int i = 1; i < root_size; ++i){
            left_cum_[root][i] = merge_(left_cum_[root][i - 1], subtree_dp_[root][i], root);
        }
        right_cum_[root].resize(root_size + 1);
        right_cum_[root].back() = id_;
        for(int i = root_size - 1; i - 1 >= 0; --i){
            right_cum_[root][i] = merge_(right_cum_[root][i + 1], subtree_dp_[root][i], root);
        }

        queue<tuple<int, int, int>> que;
        for(int i = 0; i < tree_.get_child(root).size(); ++i){
            que.push({tree_.get_child(root)[i], root, i + 1});
        }
        while(que.size()){
            auto [v, p, idx] = que.front(); que.pop();
            Monoid ret = id_;
            ret = merge_(ret, left_cum_[p][idx - 1], v);
            ret = merge_(ret, right_cum_[p][idx + 1], v);
            ret = add_(ret, tree_.get_cost(v), p);
            subtree_dp_[v].push_back(ret);
            for(int i = 1; i + 1 < subtree_dp_[v].size(); ++i){
                ret = merge_(ret, subtree_dp_[v][i], v);
            }
            dp_[v] = finalize_(ret, v);
            int c = subtree_dp_[v].size();
            left_cum_[v].resize(c + 1);
            left_cum_[v][0] = id_;
            for(int i = 1; i < c; ++i){
                left_cum_[v][i] = merge_(left_cum_[v][i - 1], subtree_dp_[v][i], v);
            }
            right_cum_[v].resize(c + 1);
            right_cum_[v].back() = id_;
            for(int i = c - 1; i - 1 >= 0; --i){
                right_cum_[v][i] = merge_(right_cum_[v][i + 1], subtree_dp_[v][i], v);
            }
            for(int i = 0; i < tree_.get_child(v).size(); ++i){
                que.push({tree_.get_child(v)[i], v, i + 1});
            }
        }
    }
    
    int V;
    vector<Monoid> dp_;
    vector<vector<Monoid>> subtree_dp_, left_cum_, right_cum_;

    const Monoid id_;

    F merge_;
    G add_;
    H finalize_;
    const Fsub merge_sub_;
    const Gsub add_sub_;
};
#line 5 "verify/AOJ-GRL-5-B.test.cpp"

int main(){
    int n; cin >> n;
    RootedTree T(n);
    T.InputGraphFormat(true, false);

    RerootingDP<int, int> dp(
        T,
        [](int l, int r){return max(l, r);},
        [](int l, int r){return l + r;},
        0);
    for(int i = 0; i < n; ++i){
        cout << dp[i] << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 6704
final_rank: 13

code_snippet: #line 1 "verify/AOJ-GRL-5-B.test.cpp"
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/library/5/GRL/5/GRL_5_B"

#line 2 "Library/Template.hpp"

/**
 * @file Template.hpp
 * @author log K (lX57)
 * @brief Template - テンプレート
 * @version 1.8
 * @date 2024-06-16
 */

#line 2 "Library/Common.hpp"

/**
 * @file Common.hpp
 */

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;
#line 12 "Library/Template.hpp"
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define SORT(x) sort(ALL(x))
#define RSORT(x) sort(RALL(x))
#define REVERSE(x) reverse(ALL(x))
#define SETPRE(digit) fixed << setprecision(digit)
#define POPCOUNT(x) __builtin_popcount(x)
#define SUM(x) reduce((x).begin(), (x).end())
#define CEIL(nume, deno) ((nume) + (deno) - 1) / (deno)
#define IOTA(x) iota((x).begin(), (x).end(), 0)
#define LOWERBOUND_IDX(arr, val) distance((arr).begin(), lower_bound((arr).begin(), (arr).end(), val))
#define UPPERBOUND_IDX(arr, val) distance((arr).begin(), upper_bound((arr).begin(), (arr).end(), val))

inline string Yn(bool flag){return (flag) ? "Yes" : "No";}
inline bool YnPrint(bool flag){cout << Yn(flag) << endl;return flag;}
inline string YN(bool flag){return (flag) ? "YES" : "NO";}
inline bool YNPrint(bool flag){cout << YN(flag) << endl;return flag;}
template<class T>
bool chmin(T &src, const T &cmp){if(src > cmp){src = cmp; return true;}return false;}
template<class T>
bool chmax(T &src, const T &cmp){if(src < cmp){src = cmp; return true;}return false;}
template<typename T>
inline bool between(T min, T x, T max){return min <= x && x <= max;}
template<typename T>
inline bool ingrid(T y, T x, T ymax, T xmax){return between(0, y, ymax - 1) && between(0, x, xmax - 1);}
template<typename T>
inline T median(T a, T b, T c){return between(b, a, c) || between(c, a, b) ? a : (between(a, b, c) || between(c, b, a) ? b : c);}
template<typename T>
inline T except(T src, T cond, T excp){return (src == cond ? excp : src);}
template<typename T>
inline T min(vector<T> &v){return *min_element((v).begin(), (v).end());}
template<typename T>
inline T max(vector<T> &v){return *max_element((v).begin(), (v).end());}
vector<int> make_sequence(int Size){
    vector<int> ret(Size);
    IOTA(ret);
    return ret;
}
template<typename T>
void make_unique(vector<T> &v){
    sort(v.begin(), v.end());
    auto itr = unique(v.begin(), v.end());
    v.erase(itr, v.end());
}

using ll = int64_t;
using ull = uint64_t;
using ld = long double;

const int INF_INT = numeric_limits<int>::max() >> 2;
const ll INF_LL = numeric_limits<ll>::max() >> 2;

using vi = vector<int>;
using vvi = vector<vi>;
using vl = vector<ll>;
using vvl = vector<vl>;
using pi = pair<int, int>;
using pl = pair<ll, ll>;
using vs = vector<string>;
template <typename T>
using pq = priority_queue<T>;
template <typename T>
using rpq = priority_queue<T, vector<T>, greater<T>>;

const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};

vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
    vector<pair<int, int>> ret;
    for(int d = 0; d < 4 * (1 + dir_8); ++d){
        int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
        int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
        if(0 <= next_y and next_y < max_y and 0 <= next_x and next_x < max_x){
            ret.emplace_back(next_y, next_x);
        }
    }
    return ret;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
    os << p.first << " " << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? "\n" : "");
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, set<T> &v){
    for (auto &u : v){
        os << u << " ";
    }
    return os;
}

template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
    assert(v1.size() == v2.size());
    vector<pair<T1, T2>> v;
    for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
    return v;
}

template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
    vector<T1> v1;
    vector<T2> v2;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
    return {v1, v2};
}

template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
    transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
    return {v1, v2, v3};
}

template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
    vector<pair<T1, T2>> v(size);
    for(auto &[p, q] : v) cin >> p >> q;
    return DisassembleVectorPair(v);
}

template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
    vector<tuple<T1, T2, T3>> v(size);
    for(auto &[p, q, r] : v) cin >> p >> q >> r;
    return DisassembleVectorTuple(v);
}

#ifdef LOGK
#define DEBUG(fmt, ...) fprintf(stderr, fmt __VA_OPT__(,) __VA_ARGS__)
#define VARIABLE(var) cerr << "# " << #var << " = " << var << endl;
#else
#define DEBUG(...) 42
#define VARIABLE(...) 42
#endif

// ==============================================================
// 
// Main Program Start
// 
// ==============================================================
#line 1 "Library/Tree/RerootingDP.hpp"
/**
 * @file RerootingDP.hpp
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-09-03
 * 
 * @copyright Copyright (c) 2024
 * 
 */

#line 2 "Library/Tree/Tree.hpp"

/**
 * @file Tree.hpp
 * @brief Tree - 木テンプレート
 * @version 0.1
 * @date 2024-07-29
 */

#line 11 "Library/Tree/Tree.hpp"

using Vertex = int;

template<typename CostType = int32_t>
class RootedTree{
    public:
    struct Node{
        Node(Vertex parent = -1) : parent(parent){}

        Vertex parent{-1};
        CostType cost{0};
        vector<Vertex> children{};
    };

    /**
     * @brief 頂点 `root_vertex` を根とする頂点数 `vertex_size` の根付き木を構築する。
     * @note 根が入力で与えられなれないが後で分かる　みたいなよく分からん状況の時は `root_vertex = -1` とするとよい
     * @param vertex_size 頂点数
     * @param root_vertex 根とする頂点 (default = 0)
     */
    RootedTree(int vertex_size, Vertex root_vertex = 0) :
            vertex_size_(vertex_size), root_vertex_(root_vertex),
            node_(vertex_size){}

    /**
     * @brief 木の頂点数を返す。
     * @return int 木の頂点数
     */
    int get_vertex_size() const {
        return vertex_size_;
    }

    /**
     * @brief 木の根の頂点を返す。
     * @return Vertex 木の根の頂点番号 (0-index)
     */
    Vertex get_root() const {
        return root_vertex_;
    }

    /**
     * @brief 頂点 `v` の親の頂点番号を返す。
     * @note `v` が根の場合、`-1` が返される。
     * @param v 子の頂点番号 (0-index)
     * @return Vertex 親の頂点番号 (0-index)
     */
    Vertex get_parent(Vertex v) const {
        Validate(v);
        return node_[v].parent;
    }

    /**
     * @brief 頂点 `v` の子の頂点番号列を返す。
     * @note 頂点番号列は入力順に返される。
     * @param v 親の頂点番号 (0-index)
     * @return vector<Vertex> 子の頂点番号列 (0-index)
     */
    vector<Vertex> &get_child(Vertex v){
        Validate(v);
        return node_[v].children;
    }

    /**
     * @brief 頂点 `v` とその親を結ぶ辺の重みを返す。
     * @attention `v` が根の場合の返り値は未定義である。
     * @param v 頂点番号 (0-index)
     * @return CostType 辺の重み
     */
    CostType get_cost(Vertex v){
        Validate(v);
        return node_[v].cost;
    }

    /**
     * @brief 頂点 `parent` から頂点 `child` への重さ `cost` の辺を張る。
     * @note `cost` を省略することで重みなし辺を張ることができる。
     * @param parent 親の頂点番号 (0-index)
     * @param child 子の頂点番号 (0-index)
     * @param cost 辺の重み (default = 1)
     */
    void AddEdge(Vertex parent, Vertex child, CostType cost = 1){
        Validate(parent);
        Validate(child);
        node_[parent].children.push_back(child);
        node_[child].parent = parent;
        node_[child].cost = cost;
    }

    /**
     * @brief `u v w` のような入力形式を受け取る。
     * @param weighted 重み付きの木であるか (default = true)
     * @param one_index 入力される頂点番号が 1-index かどうか (default = true)
     */
    void InputGraphFormat(bool weighted = true, bool one_index = true){
        vector<vector<pair<Vertex, CostType>>> graph(vertex_size_);
        for(int i = 0; i < vertex_size_ - 1; ++i){
            int u, v; cin >> u >> v;
            if(one_index) --u, --v;
            CostType w = 1;
            if(weighted) cin >> w;
            graph[u].emplace_back(v, w);
            graph[v].emplace_back(u, w);
        }
        auto rec = [&](auto self, Vertex v, Vertex p) -> void {
            for(auto [u, w] : graph[v]){
                if(u == p) continue;
                AddEdge(v, u, w);
                self(self, u, v);
            }
        };
        rec(rec, root_vertex_, -1);
    }

    /**
     * @brief `p_1 p_2 ... p_N` のような入力形式を受け取る。
     * @attention weighted の処理を書いていないので、`weighted` のパラメータに意味はない
     * @param weighted 重み付きの木であるか (default = true)
     * @param one_index 入力される頂点番号が 1-index かどうか (default = true)
     */
    void InputRootedTreeFormat(bool weighted = true, bool one_index = true){
        assert(root_vertex_ == 0);
        for(int i = 1; i < vertex_size_; ++i){
            int p; cin >> p;
            if(one_index) --p;
            AddEdge(p, i);
        }
    }

    /**
     * @brief 頂点 `v` が根の頂点か判定する。
     * @param v 判定する頂点番号 (0-index)
     */
    bool RootVertex(Vertex v){
        Validate(v);
        return node_[v].parent == -1;
    }
    
    /**
     * @brief 頂点 `v` が葉の頂点か判定する。
     * @param v 判定する頂点番号 (0-index)
     */
    bool LeafVertex(Vertex v){
        Validate(v);
        return node_[v].children.empty();
    }

    /**
     * @brief 木の根の頂点を求める。
     * @attention 基本的には不要で、根の頂点番号が与えられていない場合に用いる。
     * @note Verify : https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/7/ALDS1_7_A
     * @return Vertex 根の頂点番号
     */
    Vertex FindRoot(){
        for(int i = 0; i < vertex_size_; ++i){
            if(RootVertex(i)){
                root_vertex_ = i;
                return i;
            }
        }
        assert(false);
    }

    /**
     * @brief 木の根を変更して再構築する。
     * @param root 新しい根の頂点番号 (0-index)
     */
    void Rerooting(Vertex root){
        if(root == root_vertex_) return;
        vector<Node> new_node_(vertex_size_);
        auto rec = [&](auto self, Vertex v, Vertex p, CostType c) -> void {
            new_node_[v].parent = p;
            new_node_[v].cost = c;
            if(node_[v].parent != p && node_[v].parent != -1){
                new_node_[v].children.push_back(node_[v].parent);
                self(self, node_[v].parent, v, node_[v].cost);
            }
            for(Vertex u : node_[v].children){
                if(u != p){
                    new_node_[v].children.push_back(u);
                    self(self, u, v, node_[u].cost);
                }
            }
        };
        rec(rec, root, -1, 0);
        swap(new_node_, node_);
        root_vertex_ = root;
    }

    void Print(bool one_index = true) const {
        for(int i = 0; i < vertex_size_; ++i){
            fprintf(stderr, "# Vertex %d : parent = %d (cost = %d), children = [", i + int(one_index), get_parent(i) + int(one_index), node_[i].cost);
            for(int j = 0; j < node_[i].children.size(); ++j){
                fprintf(stderr, "%d", node_[i].children[j]);
                if(j + 1 < node_[i].children.size()){
                    fprintf(stderr, ", ");
                }
            }
            fprintf(stderr, "]\n");
        }
    }

    private:
    inline void Validate(Vertex v) const {
        assert(0 <= v && v < vertex_size_);
    }

    int vertex_size_, root_vertex_{-1};
    vector<Node> node_;
};

/**
 * @brief 木 `tree` の各頂点の深さを求める。
 * @note 根の頂点は深さ 0 である。
 * @note Verify : https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/7/ALDS1_7_A
 * @param tree 木
 * @param root 根の頂点番号 (default = 0)
 * @return vector<int> 各頂点の深さ
 */
template<typename CostType>
vector<int> CalculateTreeDepth(RootedTree<CostType> &tree){
    int V = tree.get_vertex_size();
    vector<int> ret(V, 0);
    auto rec = [&](auto self, Vertex v, int d) -> void {
        ret[v] = d;
        for(Vertex u : tree.get_child(v)){
            self(self, u, d + 1);
        }
    };
    Vertex root = tree.get_root();
    if(root < 0) root = tree.FindRoot();
    rec(rec, root, 0);
    return ret;
}

/**
 * @brief 木の根から各頂点への辺の重みの累積和を計算する。
 * @param tree 木
 * @return vector<CostType> 根から各頂点への重みの累積和
 */
template<typename CostType>
vector<CostType> CalculateTreeCumlativeSum(RootedTree<CostType> &tree){
    Vertex root = tree.get_root();
    int V = tree.get_vertex_size();
    vector<CostType> ret(V, 0);
    auto rec = [&](auto self, Vertex v, CostType s) -> void {
        ret[v] = s + tree.get_cost(v);
        for(Vertex u : tree.get_child(v)){
            self(self, u, ret[v]);
        }
    };
    rec(rec, root, 0);
    return ret;
}
#line 13 "Library/Tree/RerootingDP.hpp"

template<typename CostType, typename Monoid>
class RerootingDP{
    public:
    using F = function<Monoid(Monoid, Monoid)>;
    using G = function<Monoid(Monoid, CostType)>;

    RerootingDP(RootedTree<CostType> &tree, F merge, G add, const Monoid monoid_identity) :
            tree_(tree), V(tree.get_vertex_size()), merge_(merge), add_(add), id_(monoid_identity){
        dp_.resize(V, id_);
        subtree_dp_.resize(V, vector<Monoid>{id_});
        left_cum_.resize(V);
        right_cum_.resize(V);
        Vertex root = tree_.get_root();

        dp_[root] = dfs(root);
        int root_size = subtree_dp_[root].size();
        left_cum_[root].resize(root_size + 1);
        left_cum_[root].front() = id_;
        for(int i = 1; i < root_size; ++i){
            left_cum_[root][i] = merge_(left_cum_[root][i - 1], subtree_dp_[root][i]);
        }
        right_cum_[root].resize(root_size + 1);
        right_cum_[root].back() = id_;
        for(int i = root_size - 1; i - 1 >= 0; --i){
            right_cum_[root][i] = merge_(right_cum_[root][i + 1], subtree_dp_[root][i]);
        }

        queue<tuple<int, int, int>> que;
        for(int i = 0; i < tree_.get_child(root).size(); ++i){
            que.push({tree_.get_child(root)[i], root, i + 1});
        }
        while(que.size()){
            auto [v, p, idx] = que.front(); que.pop();
            int ret = 0;
            ret = merge_(ret, left_cum_[p][idx - 1]);
            ret = merge_(ret, right_cum_[p][idx + 1]);
            ret = add_(ret, tree_.get_cost(v));
            subtree_dp_[v].push_back(ret);
            for(Monoid cval : subtree_dp_[v]){
                ret = merge_(ret, cval);
            }
            dp_[v] = ret;
            int c = subtree_dp_[v].size();
            left_cum_[v].resize(c + 1);
            left_cum_[v][0] = 0;
            for(int i = 1; i < c; ++i){
                left_cum_[v][i] = merge_(left_cum_[v][i - 1], subtree_dp_[v][i]);
            }
            right_cum_[v].resize(c + 1);
            right_cum_[v].back() = 0;
            for(int i = c - 1; i - 1 >= 0; --i){
                right_cum_[v][i] = merge_(right_cum_[v][i + 1], subtree_dp_[v][i]);
            }
            for(int i = 0; i < tree_.get_child(v).size(); ++i){
                que.push({tree_.get_child(v)[i], v, i + 1});
            }
        }
    }

    vector<Monoid> &get_all_answer(){
        return dp_;
    }

    Monoid operator[](Vertex v){
        return dp_[v];
    }

    const Monoid operator[](Vertex v) const {
        return dp_[v];
    }

    private:
    RootedTree<CostType> &tree_;

    Monoid dfs(Vertex v){
        Monoid ret = id_;
        for(auto u : tree_.get_child(v)){
            Monoid res = dfs(u);
            subtree_dp_[v].push_back(res);
            ret = merge_(ret, res);
        }
        ret = add_(ret, tree_.get_cost(v));
        return ret;
    }
    
    int V;
    vector<Monoid> dp_;
    vector<vector<Monoid>> subtree_dp_, left_cum_, right_cum_;

    const Monoid id_;

    const F merge_;
    const G add_;
};
#line 5 "verify/AOJ-GRL-5-B.test.cpp"

int main(){
    int n; cin >> n;
    RootedTree T(n);
    T.InputGraphFormat(true, false);

    RerootingDP<int, int> dp(
        T,
        [](int l, int r){return max(l, r);},
        [](int l, int r){return l + r;},
        0);
    for(int i = 0; i < n; ++i){
        cout << dp[i] << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 6576
final_rank: 11

code_snippet: #line 2 "Library/Template.hpp"

/**
 * @file Template.hpp
 * @author log K (lX57)
 * @brief Template - テンプレート
 * @version 1.8
 * @date 2024-06-16
 */

#line 2 "Library/Common.hpp"

/**
 * @file Common.hpp
 */

#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;
#line 12 "Library/Template.hpp"
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define SORT(x) sort(ALL(x))
#define RSORT(x) sort(RALL(x))
#define REVERSE(x) reverse(ALL(x))
#define SETPRE(digit) fixed << setprecision(digit)
#define POPCOUNT(x) __builtin_popcount(x)
#define SUM(x) reduce((x).begin(), (x).end())
#define CEIL(nume, deno) ((nume) + (deno) - 1) / (deno)
#define IOTA(x) iota((x).begin(), (x).end(), 0)
#define LOWERBOUND_IDX(arr, val) distance((arr).begin(), lower_bound((arr).begin(), (arr).end(), val))
#define UPPERBOUND_IDX(arr, val) distance((arr).begin(), upper_bound((arr).begin(), (arr).end(), val))

inline string Yn(bool flag){return (flag) ? "Yes" : "No";}
inline bool YnPrint(bool flag){cout << Yn(flag) << endl;return flag;}
inline string YN(bool flag){return (flag) ? "YES" : "NO";}
inline bool YNPrint(bool flag){cout << YN(flag) << endl;return flag;}
template<class T>
bool chmin(T &src, const T &cmp){if(src > cmp){src = cmp; return true;}return false;}
template<class T>
bool chmax(T &src, const T &cmp){if(src < cmp){src = cmp; return true;}return false;}
template<typename T>
inline bool between(T min, T x, T max){return min <= x && x <= max;}
template<typename T>
inline bool ingrid(T y, T x, T ymax, T xmax){return between(0, y, ymax - 1) && between(0, x, xmax - 1);}
template<typename T>
inline T median(T a, T b, T c){return between(b, a, c) || between(c, a, b) ? a : (between(a, b, c) || between(c, b, a) ? b : c);}
template<typename T>
inline T except(T src, T cond, T excp){return (src == cond ? excp : src);}
template<typename T>
inline T min(vector<T> &v){return *min_element((v).begin(), (v).end());}
template<typename T>
inline T max(vector<T> &v){return *max_element((v).begin(), (v).end());}
vector<int> make_sequence(int Size){
    vector<int> ret(Size);
    IOTA(ret);
    return ret;
}
template<typename T>
void make_unique(vector<T> &v){
    sort(v.begin(), v.end());
    auto itr = unique(v.begin(), v.end());
    v.erase(itr, v.end());
}

using ll = int64_t;
using ull = uint64_t;
using ld = long double;

const int INF_INT = numeric_limits<int>::max() >> 2;
const ll INF_LL = numeric_limits<ll>::max() >> 2;

using vi = vector<int>;
using vvi = vector<vi>;
using vl = vector<ll>;
using vvl = vector<vl>;
using pi = pair<int, int>;
using pl = pair<ll, ll>;
using vs = vector<string>;
template <typename T>
using pq = priority_queue<T>;
template <typename T>
using rpq = priority_queue<T, vector<T>, greater<T>>;

const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};

vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
    vector<pair<int, int>> ret;
    for(int d = 0; d < 4 * (1 + dir_8); ++d){
        int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
        int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
        if(0 <= next_y and next_y < max_y and 0 <= next_x and next_x < max_x){
            ret.emplace_back(next_y, next_x);
        }
    }
    return ret;
}

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
    os << p.first << " " << p.second;
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? "\n" : "");
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, set<T> &v){
    for (auto &u : v){
        os << u << " ";
    }
    return os;
}

template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
    assert(v1.size() == v2.size());
    vector<pair<T1, T2>> v;
    for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
    return v;
}

template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
    vector<T1> v1;
    vector<T2> v2;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
    return {v1, v2};
}

template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
    transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
    transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
    return {v1, v2, v3};
}

template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
    vector<pair<T1, T2>> v(size);
    for(auto &[p, q] : v) cin >> p >> q;
    return DisassembleVectorPair(v);
}

template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
    vector<tuple<T1, T2, T3>> v(size);
    for(auto &[p, q, r] : v) cin >> p >> q >> r;
    return DisassembleVectorTuple(v);
}

#ifdef LOGK
#define DEBUG(fmt, ...) fprintf(stderr, fmt __VA_OPT__(,) __VA_ARGS__)
#define VARIABLE(var) cerr << "# " << #var << " = " << var << endl;
#else
#define DEBUG(...) 42
#define VARIABLE(...) 42
#endif

// ==============================================================
// 
// Main Program Start
// 
// ==============================================================
#line 2 "Library/Tree/Tree.hpp"

/**
 * @file Tree.hpp
 * @brief Tree - 木テンプレート
 * @version 0.1
 * @date 2024-07-29
 */

#line 11 "Library/Tree/Tree.hpp"

using Vertex = int;

template<typename CostType = int32_t>
class RootedTree{
    public:
    struct Node{
        Node(Vertex parent = -1) : parent(parent){}

        Vertex parent{-1};
        CostType cost{0};
        vector<Vertex> children{};
    };

    /**
     * @brief 頂点 `root_vertex` を根とする頂点数 `vertex_size` の根付き木を構築する。
     * @note 根が入力で与えられなれないが後で分かる　みたいなよく分からん状況の時は `root_vertex = -1` とするとよい
     * @param vertex_size 頂点数
     * @param root_vertex 根とする頂点 (default = 0)
     */
    RootedTree(int vertex_size, Vertex root_vertex = 0) :
            vertex_size_(vertex_size), root_vertex_(root_vertex),
            node_(vertex_size){}

    /**
     * @brief 木の頂点数を返す。
     * @return int 木の頂点数
     */
    int get_vertex_size() const {
        return vertex_size_;
    }

    /**
     * @brief 木の根の頂点を返す。
     * @return Vertex 木の根の頂点番号 (0-index)
     */
    Vertex get_root() const {
        return root_vertex_;
    }

    /**
     * @brief 頂点 `v` の親の頂点番号を返す。
     * @note `v` が根の場合、`-1` が返される。
     * @param v 子の頂点番号 (0-index)
     * @return Vertex 親の頂点番号 (0-index)
     */
    Vertex get_parent(Vertex v) const {
        Validate(v);
        return node_[v].parent;
    }

    /**
     * @brief 頂点 `v` の子の頂点番号列を返す。
     * @note 頂点番号列は入力順に返される。
     * @param v 親の頂点番号 (0-index)
     * @return vector<Vertex> 子の頂点番号列 (0-index)
     */
    vector<Vertex> &get_child(Vertex v){
        Validate(v);
        return node_[v].children;
    }

    /**
     * @brief 頂点 `v` とその親を結ぶ辺の重みを返す。
     * @attention `v` が根の場合の返り値は未定義である。
     * @param v 頂点番号 (0-index)
     * @return CostType 辺の重み
     */
    CostType get_cost(Vertex v){
        Validate(v);
        return node_[v].cost;
    }

    /**
     * @brief 頂点 `parent` から頂点 `child` への重さ `cost` の辺を張る。
     * @note `cost` を省略することで重みなし辺を張ることができる。
     * @param parent 親の頂点番号 (0-index)
     * @param child 子の頂点番号 (0-index)
     * @param cost 辺の重み (default = 1)
     */
    void AddEdge(Vertex parent, Vertex child, CostType cost = 1){
        Validate(parent);
        Validate(child);
        node_[parent].children.push_back(child);
        node_[child].parent = parent;
        node_[child].cost = cost;
    }

    /**
     * @brief `u v w` のような入力形式を受け取る。
     * @param weighted 重み付きの木であるか (default = true)
     * @param one_index 入力される頂点番号が 1-index かどうか (default = true)
     */
    void InputGraphFormat(bool weighted = true, bool one_index = true){
        vector<vector<pair<Vertex, CostType>>> graph(vertex_size_);
        for(int i = 0; i < vertex_size_ - 1; ++i){
            int u, v; cin >> u >> v;
            if(one_index) --u, --v;
            CostType w = 1;
            if(weighted) cin >> w;
            graph[u].emplace_back(v, w);
            graph[v].emplace_back(u, w);
        }
        auto rec = [&](auto self, Vertex v, Vertex p) -> void {
            for(auto [u, w] : graph[v]){
                if(u == p) continue;
                AddEdge(v, u, w);
                self(self, u, v);
            }
        };
        rec(rec, root_vertex_, -1);
    }

    /**
     * @brief `p_1 p_2 ... p_N` のような入力形式を受け取る。
     * @attention weighted の処理を書いていないので、`weighted` のパラメータに意味はない
     * @param weighted 重み付きの木であるか (default = true)
     * @param one_index 入力される頂点番号が 1-index かどうか (default = true)
     */
    void InputRootedTreeFormat(bool weighted = true, bool one_index = true){
        assert(root_vertex_ == 0);
        for(int i = 1; i < vertex_size_; ++i){
            int p; cin >> p;
            if(one_index) --p;
            AddEdge(p, i);
        }
    }

    /**
     * @brief 頂点 `v` が根の頂点か判定する。
     * @param v 判定する頂点番号 (0-index)
     */
    bool RootVertex(Vertex v){
        Validate(v);
        return node_[v].parent == -1;
    }
    
    /**
     * @brief 頂点 `v` が葉の頂点か判定する。
     * @param v 判定する頂点番号 (0-index)
     */
    bool LeafVertex(Vertex v){
        Validate(v);
        return node_[v].children.empty();
    }

    /**
     * @brief 木の根の頂点を求める。
     * @attention 基本的には不要で、根の頂点番号が与えられていない場合に用いる。
     * @note Verify : https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/7/ALDS1_7_A
     * @return Vertex 根の頂点番号
     */
    Vertex FindRoot(){
        for(int i = 0; i < vertex_size_; ++i){
            if(RootVertex(i)){
                root_vertex_ = i;
                return i;
            }
        }
        assert(false);
    }

    /**
     * @brief 木の根を変更して再構築する。
     * @param root 新しい根の頂点番号 (0-index)
     */
    void Rerooting(Vertex root){
        if(root == root_vertex_) return;
        vector<Node> new_node_(vertex_size_);
        auto rec = [&](auto self, Vertex v, Vertex p, CostType c) -> void {
            new_node_[v].parent = p;
            new_node_[v].cost = c;
            if(node_[v].parent != p && node_[v].parent != -1){
                new_node_[v].children.push_back(node_[v].parent);
                self(self, node_[v].parent, v, node_[v].cost);
            }
            for(Vertex u : node_[v].children){
                if(u != p){
                    new_node_[v].children.push_back(u);
                    self(self, u, v, node_[u].cost);
                }
            }
        };
        rec(rec, root, -1, 0);
        swap(new_node_, node_);
        root_vertex_ = root;
    }

    void Print(bool one_index = true) const {
        for(int i = 0; i < vertex_size_; ++i){
            fprintf(stderr, "# Vertex %d : parent = %d (cost = %d), children = [", i + int(one_index), get_parent(i) + int(one_index), node_[i].cost);
            for(int j = 0; j < node_[i].children.size(); ++j){
                fprintf(stderr, "%d", node_[i].children[j]);
                if(j + 1 < node_[i].children.size()){
                    fprintf(stderr, ", ");
                }
            }
            fprintf(stderr, "]\n");
        }
    }

    private:
    inline void Validate(Vertex v) const {
        assert(0 <= v && v < vertex_size_);
    }

    int vertex_size_, root_vertex_{-1};
    vector<Node> node_;
};

/**
 * @brief 木 `tree` の各頂点の深さを求める。
 * @note 根の頂点は深さ 0 である。
 * @note Verify : https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/7/ALDS1_7_A
 * @param tree 木
 * @param root 根の頂点番号 (default = 0)
 * @return vector<int> 各頂点の深さ
 */
template<typename CostType>
vector<int> CalculateTreeDepth(RootedTree<CostType> &tree){
    int V = tree.get_vertex_size();
    vector<int> ret(V, 0);
    auto rec = [&](auto self, Vertex v, int d) -> void {
        ret[v] = d;
        for(Vertex u : tree.get_child(v)){
            self(self, u, d + 1);
        }
    };
    Vertex root = tree.get_root();
    if(root < 0) root = tree.FindRoot();
    rec(rec, root, 0);
    return ret;
}

/**
 * @brief 木の根から各頂点への辺の重みの累積和を計算する。
 * @param tree 木
 * @return vector<CostType> 根から各頂点への重みの累積和
 */
template<typename CostType>
vector<CostType> CalculateTreeCumlativeSum(RootedTree<CostType> &tree){
    Vertex root = tree.get_root();
    int V = tree.get_vertex_size();
    vector<CostType> ret(V, 0);
    auto rec = [&](auto self, Vertex v, CostType s) -> void {
        ret[v] = s + tree.get_cost(v);
        for(Vertex u : tree.get_child(v)){
            self(self, u, ret[v]);
        }
    };
    rec(rec, root, 0);
    return ret;
}
#line 3 "Library/test.cpp"

int main(){
    int n; cin >> n;
    RootedTree T(n);
    T.InputGraphFormat(true, false);

    // T.Print(false);

    // 頂点 `i` を根とする DP の解
    vector<int> dp(n, 0);
    // 頂点 `i` の各部分木の DP の解(非根については末尾に親の部分木)
    vector<vector<int>> subtree_dp(n, vector<int>{0});
    // `subtree_dp[i]` の左右からの累積
    vector<vector<int>> left_subtree_cum(n), right_subtree_cum(n);

    // DFS
    auto dfs = [&](auto self, int v) -> int {
        int ret = 0;
        for(auto u : T.get_child(v)){
            int res = self(self, u);
            subtree_dp[v].push_back(res);
            ret = max(ret, res);
        }
        ret = ret + T.get_cost(v);
        return ret;
    };
    dp[0] = dfs(dfs, 0);
    int c = subtree_dp[0].size();
    left_subtree_cum[0].resize(c + 1);
    left_subtree_cum[0][0] = 0;
    for(int i = 1; i < c; ++i){
        left_subtree_cum[0][i] = max(left_subtree_cum[0][i - 1], subtree_dp[0][i]);
    }
    right_subtree_cum[0].resize(c + 1);
    right_subtree_cum[0].back() = 0;
    for(int i = c - 1; i - 1 >= 0; --i){
        right_subtree_cum[0][i] = max(right_subtree_cum[0][i + 1], subtree_dp[0][i]);
    }

    // BFS しながら全方位木 DP をする

    // {頂点番号, 親の頂点番号, 親の頂点の何番目の子か (1-index)}
    queue<tuple<int, int, int>> que;
    for(int i = 0; i < T.get_child(0).size(); ++i){
        que.push({T.get_child(0)[i], 0, i + 1});
    }
    while(que.size()){
        auto [v, p, idx] = que.front(); que.pop();
        int ret = 0;
        ret = max(ret, left_subtree_cum[p][idx - 1]);
        ret = max(ret, right_subtree_cum[p][idx + 1]);
        ret = ret + T.get_cost(v);
        subtree_dp[v].push_back(ret);
        for(auto cval : subtree_dp[v]){
            ret = max(ret, cval);
        }
        dp[v] = ret;
        int c = subtree_dp[v].size();
        left_subtree_cum[v].resize(c + 1);
        left_subtree_cum[v][0] = 0;
        for(int i = 1; i < c; ++i){
            left_subtree_cum[v][i] = max(left_subtree_cum[v][i - 1], subtree_dp[v][i]);
        }
        right_subtree_cum[v].resize(c + 1);
        right_subtree_cum[v].back() = 0;
        for(int i = c - 1; i - 1 >= 0; --i){
            right_subtree_cum[v][i] = max(right_subtree_cum[v][i + 1], subtree_dp[v][i]);
        }
        for(int i = 0; i < T.get_child(v).size(); ++i){
            que.push({T.get_child(v)[i], v, i + 1});
        }
    }
    for(auto v : dp){
        cout << v << endl;
    }
    
    // cerr << "# dp table :";
    // for(int i = 0; i < n; ++i){
    //     cerr << " " << dp[i];
    // }
    // cerr << endl;
    // cerr << "# subtree_dp table" << endl;
    // for(int i = 0; i < n; ++i){
    //     cerr << "# vertex " << i << endl;
    //     cerr << "#    subtree_dp :";
    //     for(int j = 0; j < subtree_dp[i].size(); ++j){
    //         cerr << " " << subtree_dp[i][j];
    //     }
    //     cerr << endl;
    //     cerr << "#    left_cum   :";
    //     for(int j = 0; j < left_subtree_cum[i].size(); ++j){
    //         cerr << " " << left_subtree_cum[i][j];
    //     }
    //     cerr << endl;
    //     cerr << "#    right_cum  :";
    //     for(int j = 0; j < right_subtree_cum[i].size(); ++j){
    //         cerr << " " << right_subtree_cum[i][j];
    //     }
    //     cerr << endl;
    // }
}
accuracy: 1
time_ms: 10
memory_kb: 6576
final_rank: 11

code_snippet: #include <bits/stdc++.h>

using namespace std;

// long longの省略
typedef long long ll;

// rep(先頭にRで逆からループ、末尾にSで「1～n」となる)
#define rep(i, a, n) for(int i = a; i < n; i++)
#define reps(i, a, n) for(int i = a; i <= n; i++)
#define rrep(i, a, n) for(int i = n - 1; i >= a; i--)
#define rreps(i, a, n) for(int i = n; i >= a; i--)

// ソートなどに対象を入れる場合
#define all(x) (x).begin(),(x).end()

// ソートされた配列から重複を削除して詰めなおす
#define UNIQUE(x) x.erase( unique(x.begin(), x.end()), x.end() );

int d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

int __gcd(int a, int b){
	int c;

	while((c = a % b) != 0){
		a = b;
		b = c;
	}

	return b;
}

// 「number」の「n」ビット目が「1」であるか「0」か
// ビット目の数え方は配列の添え字と同じ
bool __bit(int number, int n){
	if(number & (1 << n))
		return true;

	return false;
}

// aよりもbが大きいならばaをbで更新する
// (更新されたならばtrueを返す)
template <typename T>
bool chmax(T &a, const T& b) {
	if (a < b) {
		a = b;  // aをbで更新
		return true;
	}

	return false;
}
// aよりもbが小さいならばaをbで更新する
// (更新されたならばtrueを返す)
template <typename T>
bool chmin(T &a, const T& b) {
	if (a > b) {
		a = b;  // aをbで更新
	return true;
	}

	return false;
}

ll mod_pow(ll a, ll n, ll mod) {
	ll res = 1;
	// n を 2進数に変換して考える
	while (n > 0) {
		if (n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res;
}

using P = pair<int, int>;

int main()
{
	int N; cin >> N;

	vector<vector<P>> G(20000);
	rep(i, 0, N - 1){
		int a, b, c; cin >> a >> b >> c;
		G[a].push_back({b, c});
		G[b].push_back({a, c});
	}

	// 木だからダイクストラ法でなくて良い
	auto dist = [&](int start, vector<int> &array){
		queue<int> que;
		que.push(start);
		array[start] = 0;

		while(!que.empty()){
			int curr = que.front(); que.pop();

			for(auto [to, cost] : G[curr]){
				if(array[to] > array[curr] + cost){
					array[to] = array[curr] + cost;
					que.push(to);
				}
			}
		}
	};

	vector<int> v1(N, INT_MAX), v2(N, INT_MAX), v3(N, INT_MAX);
	dist(0, v1);
	dist(max_element(all(v1)) - v1.begin(), v2);
	dist(max_element(all(v2)) - v2.begin(), v3);

	rep(i, 0, N)
		cout << max(v2[i], v3[i]) << endl;

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4196
final_rank: 5

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define INF 1e9
typedef vector<int> Vec;
typedef pair<int,int> pii;

// エッジを表す構造体
struct Edge {
    int to, cost;
    Edge(int to, int cost) : to(to), cost(cost) {}
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

int N;  // ノード数
Graph G;  // グラフの隣接リスト表現

// ダイクストラ法による単一始点最短経路アルゴリズム
Vec dijkstra(int s) {
    Vec dist(N, INF);
    dist[s] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> Q;
    Q.push(pii(0, s));
    while (!Q.empty()) {
        pii p = Q.top(); Q.pop();
        int v = p.second;
        if (dist[v] < p.first) {
            continue;
        }
        for (int i = 0; i < (int)G[v].size(); i++) {
            Edge &e = G[v][i];
            if (dist[v] + e.cost < dist[e.to]) {
                dist[e.to] = dist[v] + e.cost;
                Q.push(pii(dist[e.to], e.to));
            }
        }
    }
    return dist;
}

// 指定されたノードから最も遠いノードを取得
int getFarthestPoint(int v) {
    Vec vec = dijkstra(v);
    int resv = -1, max = -1;
    for (int i = 0; i < N; i++) {
        if (max < vec[i]) {
            max = vec[i];
            resv = i;
        }
    }
    return resv;
}

// 木の各ノードの高さを計算
Vec getTreeHeight() {
    int v1 = getFarthestPoint(0);  // 任意の点から最も遠い点を取得
    int v2 = getFarthestPoint(v1); // その点からさらに最も遠い点を取得
    Vec d1 = dijkstra(v1), d2 = dijkstra(v2);
    Vec res(N);
    for (int i = 0; i < N; i++) {
        res[i] = max(d1[i], d2[i]); // 2つの最遠点からの距離のうち、大きい方を取る
    }
    return res;
}

int main() {
    int a, b, c;
    cin >> N;
    G.resize(N);
    for (int i = 0; i < N - 1; i++) {
        cin >> a >> b >> c;
        G[a].push_back(Edge(b, c));
        G[b].push_back(Edge(a, c));
    }
    Vec height = getTreeHeight();
    for (int i = 0; i < N; i++) {
        cout << height[i] << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3972
final_rank: 2

code_snippet: #include <iostream>
#include <cassert>
#include <string>
#include <stack>
#include <algorithm>
#include <vector>

using namespace std;
using ll = long long;
using Pi = pair<int, int>;

// const ll INF = 1LL << 60;
const int INF = 1001001001;
const int NIL = -1;

void dfs(const vector< vector<Pi> >& edges, int node, int cost, vector<int> &dist) {
    for (const Pi& p : edges[node]) {
        if(dist[p.first] == NIL) {
            int c = cost + p.second;
            dist[p.first] = c;
            dfs(edges, p.first, c, dist);
        }
    }
}

int main()
{
    int N, s, t, w;
    cin >> N;
    vector< vector<Pi> > edges(N);
    vector<int> dist1(N, NIL), dist2(N, NIL);
    for (int i=0;i<N-1;++i) {
        cin >> s >> t >> w;
        edges[s].push_back(make_pair(t, w));
        edges[t].push_back(make_pair(s, w));
    }

    // 任意のノードから最大遠のノードを求める
    dist1[0] = 0;
    dfs(edges, 0, 0, dist1);
    int node1, d = -1;
    for (int i=0;i<N;++i) {
        if (d < dist1[i]) {
            d = dist1[i];
            node1 = i;
        }
    }

    // 求めたノードから最大遠を求める
    dist1.assign(N, NIL);
    dist1[node1] = 0;
    dfs(edges, node1, 0, dist1);
    d = -1;
    int node2 = -1;
    for (int i=0;i<N;++i) {
        if (d < dist1[i]) {
            d = dist1[i];
            node2 = i;
        }
    }

    // さらに求めたノードからの距離を求める
    dist2[node2] = 0;
    dfs(edges, node2, 0, dist2);

    for (int i=0;i<N;++i) {
        cout << max(dist1[i], dist2[i]) << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 4228
final_rank: 6

code_snippet: // #pragma GCC target("avx2")
// #pragma GCC optimize("O3")
// #pragma GCC optimize("unroll-loops")

#define CONSTANTS
#pragma GCC diagnostic ignored "-Wunused-parameter"
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;

constexpr long long INF = 1e18;
// constexpr long long INF = LONG_LONG_MAX;
// constexpr int MOD = 1000000007;
constexpr int MOD = 998244353;
constexpr long double EPS = 1e-10;
constexpr long double PI = M_PI;

using ll = long long; using ull = unsigned long long; using ld = long double; using pll = pair<ll, ll>; using pii = pair<int, int>; using pli = pair<ll, int>; using pil = pair<int, ll>; template<typename T> using vv = vector<vector<T>>; using vvl = vv<ll>; using vvi = vv<int>; using vvpll = vv<pll>; using vvpli = vv<pli>; using vvpil = vv<pil>;
#define name4(i, a, b, c, d, e, ...) e
#define rep(...) name4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define rep1(i, a) for (ll i = 0, _aa = a; i < _aa; i++)
#define rep2(i, a, b) for (ll i = a, _bb = b; i < _bb; i++)
#define rep3(i, a, b, c) for (ll i = a, _bb = b; (c > 0 && a <= i && i < _bb) or (c < 0 && a >= i && i > _bb); i += c)
#define rrep(i, a, b) for (ll i=(a); i>(b); i--)
#define pb push_back
#define eb emplace_back
#define mkp make_pair
#define ALL(A) begin(A), end(A)
#define UNIQUE(A) sort(ALL(A)), A.erase(unique(ALL(A)), A.end())
#define elif else if
#define tostr to_string
#ifndef CONSTANTS
constexpr ll INF = 1e18; constexpr int MOD = 1000000007; constexpr ld EPS = 1e-10; constexpr ld PI = M_PI;
#endif
template<typename T1, typename T2> istream &operator>>(istream &is, pair<T1, T2> &p) { is >> p.first >> p.second; return is; } template<typename T> istream &operator>>(istream &is, vector<T> &v) { for (T &in : v) is >> in; return is; } template<typename T = ll> vector<T> LIST(int N) { vector<T> A(N); rep(i, N) { cin >> A[i]; } return A; }
template<typename T> bool chmax(T &x, T y) { return (y > x) ? x = y, true : false; }
template<typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &p) { return os << p.first << ' ' << p.second; } template<class T, size_t... Is> void print_tuple(ostream &os, const T &arg, index_sequence<Is...>) { static_cast<void>(((os << (Is == 0 ? "" : " "), os << get<Is>(arg)), ...)); } template<class... Ts> ostream &operator<<(ostream &os, const tuple<Ts...> &arg) { print_tuple(os, arg, make_index_sequence<sizeof...(Ts)>()); return os; } template<typename T, size_t N> ostream &operator<<(ostream &os, const array<T, N> &arr) { rep(i, N) { os << arr[i]; if (i != (int)N - 1) { os << ' '; } } return os; } template<typename T, size_t N> void print(const array<T, N> &arr, string sep = " ") { rep(i, N) { cout << arr[i]; if (i != (int)N - 1) cout << sep; } cout << '\n'; } template<typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { rep(i, vec.size()) { os << vec[i]; if (i != (int)vec.size() - 1) { os << ' '; } } return os; } template<typename T> void print(const vector<T> &vec, string sep = " ") { rep(i, vec.size()) { cout << vec[i]; if (i != (int)vec.size() - 1) cout << sep; } cout << '\n'; } template<typename T> void print(const deque<T> &que, string sep = " ") { vector<T> vec(ALL(que)); print(vec, sep); } template<typename T> void print(const set<T> &se, string sep = " ") { vector<T> vec(ALL(se)); print(vec, sep); } template<typename T> void print(const initializer_list<T> &li, string sep = " ") { vector<T> V(ALL(li)); print(V, sep); } void print() { cout << '\n'; } template<typename T> void print(T out) { cout << out << '\n'; }
#define debug(...) multi_debug(#__VA_ARGS__, __VA_ARGS__)
template<typename T> void multi_debug(string name, const vv<T> &grid) { cerr << name << ":" << endl; int H = grid.size(); int W = grid[0].size(); vector<int> mxlen(W); rep(h, H) { rep(w, W) { chmax(mxlen[w], (int)tostr(grid[h][w]).size()); } } rep(h, H) { rep(w, W) { int pad = mxlen[w] - (int)tostr(grid[h][w]).size(); cerr << string(pad, ' ') << grid[h][w]; if (w == W - 1) { cerr << endl; } else { cerr << ' '; } } } } template<class Tp, class... Ts> void multi_debug(string names, Tp arg, Ts... args) { if constexpr (sizeof...(Ts) == 0) { while (names.back() == ' ') { names.pop_back(); } cerr << names << ": " << arg << endl; } else { int n = names.size(), comma_pos = -1, paren_depth = 0, inside_quote = false; rep(i, n) { if (not inside_quote and paren_depth == 0 and names[i] == ',') { comma_pos = i; break; } if (names[i] == '\"' or names[i] == '\'') { if (i > 0 and names[i - 1] == '\\') continue; inside_quote ^= true; } if (not inside_quote and names[i] == '(') { paren_depth++; } if (not inside_quote and names[i] == ')') { paren_depth--; } } assert(comma_pos != -1); string name = names.substr(0, comma_pos); while (name.back() == ' ') { name.pop_back(); } cerr << name << ": " << arg << endl; int next_begin_at = comma_pos + 1; while (names[next_begin_at] == ' ') { next_begin_at++; } names = names.substr(next_begin_at); multi_debug(names, args...); } } template<typename T> void print(const vector<T> &V, char sep) { print(V, string{sep}); } template<typename T, size_t N> void print(const array<T, N> &arr, char sep) { print(arr, string{sep}); }

namespace DynamicRerootingImpl { template<typename Point, Point (*rake)(const Point &, const Point &)> struct SplayTreeforDashedEdge { struct Node { Node *l, *r, *p; Point key, sum; explicit Node(const Point &_key) : l(nullptr), r(nullptr), p(nullptr), key(_key), sum(_key) { } }; SplayTreeforDashedEdge() { } using NP = Node *; void rotr(NP t) { NP x = t->p, y = x->p; if ((x->l = t->r)) t->r->p = x; t->r = x, x->p = t; update(x), update(t); if ((t->p = y)) { if (y->l == x) y->l = t; if (y->r == x) y->r = t; } } void rotl(NP t) { NP x = t->p, y = x->p; if ((x->r = t->l)) t->l->p = x; t->l = x, x->p = t; update(x), update(t); if ((t->p = y)) { if (y->l == x) y->l = t; if (y->r == x) y->r = t; } } void update(NP t) { t->sum = t->key; if (t->l) t->sum = rake(t->sum, t->l->sum); if (t->r) t->sum = rake(t->sum, t->r->sum); } NP get_right(NP t) { while (t->r) t = t->r; return t; } NP alloc(const Point &v) { auto t = new Node(v); update(t); return t; } void splay(NP t) { while (t->p) { NP q = t->p; if (!q->p) { if (q->l == t) rotr(t); else rotl(t); } else { NP r = q->p; if (r->l == q) { if (q->l == t) rotr(q), rotr(t); else rotl(t), rotr(t); } else { if (q->r == t) rotl(q), rotl(t); else rotr(t), rotl(t); } } } } NP insert(NP t, const Point &v) { if (not t) { t = alloc(v); return t; } else { NP cur = get_right(t), z = alloc(v); splay(cur); z->p = cur; cur->r = z; update(cur); splay(z); return z; } } NP erase(NP t) { splay(t); NP x = t->l, y = t->r; delete t; if (not x) { t = y; if (t) t->p = nullptr; } else if (not y) { t = x; t->p = nullptr; } else { x->p = nullptr; t = get_right(x); splay(t); t->r = y; y->p = t; update(t); } return t; } }; template< typename Path, typename Point, typename Info, Path (*vertex)(const Info &), Path (*compress)(const Path &, const Path &), Point (*rake)(const Point &, const Point &), Point (*add_edge)(const Path &), Path (*add_vertex)(const Point &, const Info &)> struct TopTree { private: struct Node { Node *l, *r, *p; Info info; Path key, sum, mus; typename SplayTreeforDashedEdge<Point, rake>::Node *light, *belong; bool rev; bool is_root() const { return not p or (p->l != this and p->r != this); } explicit Node(const Info _info) : l(nullptr), r(nullptr), p(nullptr), info(_info), light(nullptr), belong(nullptr), rev(false) { } }; public: using NP = Node *; SplayTreeforDashedEdge<Point, rake> splay_tree; private: void toggle(NP t) { swap(t->l, t->r); swap(t->sum, t->mus); t->rev ^= true; } void rotr(NP t) { NP x = t->p, y = x->p; push(x), push(t); if ((x->l = t->r)) t->r->p = x; t->r = x, x->p = t; update(x), update(t); if ((t->p = y)) { if (y->l == x) y->l = t; if (y->r == x) y->r = t; } } void rotl(NP t) { NP x = t->p, y = x->p; push(x), push(t); if ((x->r = t->l)) t->l->p = x; t->l = x, x->p = t; update(x), update(t); if ((t->p = y)) { if (y->l == x) y->l = t; if (y->r == x) y->r = t; } } public: TopTree() : splay_tree{} { } void push(NP t) { if (t->rev) { if (t->l) toggle(t->l); if (t->r) toggle(t->r); t->rev = false; } } void push_rev(NP t) { if (t->rev) { if (t->l) toggle(t->l); if (t->r) toggle(t->r); t->rev = false; } } void update(NP t) { Path key = t->light ? add_vertex(t->light->sum, t->info) : vertex(t->info); Path sum = key, mus = key; if (t->l) sum = compress(t->l->sum, sum), mus = compress(mus, t->l->mus); if (t->r) sum = compress(sum, t->r->sum), mus = compress(t->r->mus, mus); t->key = key, t->sum = sum, t->mus = mus; } void splay(NP t) { push(t); { NP rot = t; while (not rot->is_root()) rot = rot->p; t->belong = rot->belong; if (t != rot) rot->belong = nullptr; } while (not t->is_root()) { NP q = t->p; if (q->is_root()) { push_rev(q), push_rev(t); if (q->l == t) rotr(t); else rotl(t); } else { NP r = q->p; push_rev(r), push_rev(q), push_rev(t); if (r->l == q) { if (q->l == t) rotr(q), rotr(t); else rotl(t), rotr(t); } else { if (q->r == t) rotl(q), rotl(t); else rotr(t), rotl(t); } } } } NP expose(NP t) { NP rp = nullptr; for (NP cur = t; cur; cur = cur->p) { splay(cur); if (cur->r) { cur->light = splay_tree.insert(cur->light, add_edge(cur->r->sum)); cur->r->belong = cur->light; } cur->r = rp; if (cur->r) { splay_tree.splay(cur->r->belong); push(cur->r); cur->light = splay_tree.erase(cur->r->belong); } update(cur); rp = cur; } splay(t); return rp; } void link(NP child, NP parent) { expose(parent); expose(child); child->p = parent; parent->r = child; update(parent); } void cut(NP child) { expose(child); NP parent = child->l; child->l = nullptr; parent->p = nullptr; update(child); } void evert(NP t) { expose(t); toggle(t); push(t); } NP alloc(const Info &info) { NP t = new Node(info); update(t); return t; } bool is_connected(NP u, NP v) { expose(u), expose(v); return u == v or u->p; } NP lca(NP u, NP v) { if (not is_connected(u, v)) return nullptr; expose(u); return expose(v); } void set_key(NP t, const Info &v) { expose(t); t->info = v; update(t); } Path query(NP u) { evert(u); return u->sum; } Path query_subtree(NP root, NP u) { evert(root); expose(u); NP l = u->l; u->l = nullptr; update(u); auto ret = u->sum; u->l = l; update(u); return ret; } }; template< typename Path, typename Point, typename Info, Path (*vertex)(const Info &), Path (*compress)(const Path &, const Path &), Point (*rake)(const Point &, const Point &), Point (*Add_edge)(const Path &), Path (*_add_vertex)(const Point &, const Info &)> struct DynamicRerooting { int n; TopTree<Path, Point, Info, vertex, compress, rake, Add_edge, _add_vertex> tt; using NP = typename decltype(tt)::NP; vector<NP> vs; DynamicRerooting(int _n, const vector<Info> &info) : n(_n), vs(n) { for (int i = 0; i < n; i++) vs[i] = tt.alloc(info[i]); } DynamicRerooting() : n(0) {} void add_vertex(Info info) { vs.pb(tt.alloc(info)); n++; } void add_edge(int u, int v) { tt.evert(vs[u]); tt.link(vs[u], vs[v]); } void remove_edge(int u, int v) { tt.evert(vs[u]); tt.cut(vs[v]); } Info get_info(int u) { return vs[u]->info; } void set_info(int u, const Info &info) { tt.set_key(vs[u], info); } Path query(int u) { return tt.query(vs[u]); } Path query_subtree(int root, int u) { return tt.query_subtree(vs[root], vs[u]); } }; } using DynamicRerootingImpl::DynamicRerooting;

// mx := 最遠点への距離
// ptoc := 上下接点間の距離
struct Path {
    ll mx;
    ll ptoc;
};
using Point = ll;
using Info = ll;
Path vertex(const Info &val) {
    Path res;
    res.mx = val;
    res.ptoc = val;
    return res;
}
Path compress(const Path &p, const Path &c) {
    Path res;
    //「pの最遠点」と「pの接点間+cの最遠点」を比較
    res.mx = max(p.mx, p.ptoc + c.mx);
    res.ptoc = p.ptoc + c.ptoc;
    return res;
}
Point rake(const Point &a, const Point &b) {
    return max(a, b);
}
Point add_edge(const Path &a) {
    return a.mx;
}
Path add_vertex(const Point &a, const Info &val) {
    Path res;
    res.mx = a + val;
    res.ptoc = val;
    return res;
}
using DRR = DynamicRerooting<Path, Point, Info, vertex, compress, rake, add_edge, add_vertex>;

void solve() {
    ll N;
    cin >> N;
    vector<Info> info(N * 2 - 1);
    vector<pii> edges;
    rep(i, N - 1) {
        ll u, v, w;
        cin >> u >> v >> w;
        edges.eb(u, N + i);
        edges.eb(v, N + i);
        info[N + i] = w;
    }
    DRR drr(N * 2 - 1, info);
    for (auto [u, v] : edges) {
        drr.add_edge(u, v);
    }

    rep(u, N) {
        ll res = drr.query(u).mx;
        print(res);
    }
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(15);

    // single test case
    solve();

    // multi test cases
    // int T;
    // cin >> T;
    // while (T--) solve();

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 6848
final_rank: 14

code_snippet: // #pragma GCC target("avx2")
// #pragma GCC optimize("O3")
// #pragma GCC optimize("unroll-loops")

#define CONSTANTS
#pragma GCC diagnostic ignored "-Wunused-parameter"
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;

constexpr long long INF = 1e18;
// constexpr long long INF = LONG_LONG_MAX;
// constexpr int MOD = 1000000007;
constexpr int MOD = 998244353;
constexpr long double EPS = 1e-10;
constexpr long double PI = M_PI;

using ll = long long; using ull = unsigned long long; using ld = long double; using pll = pair<ll, ll>; using pii = pair<int, int>; using pli = pair<ll, int>; using pil = pair<int, ll>; template<typename T> using vv = vector<vector<T>>; using vvl = vv<ll>; using vvi = vv<int>; using vvpll = vv<pll>; using vvpli = vv<pli>; using vvpil = vv<pil>;
#define name4(i, a, b, c, d, e, ...) e
#define rep(...) name4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define rep1(i, a) for (ll i = 0, _aa = a; i < _aa; i++)
#define rep2(i, a, b) for (ll i = a, _bb = b; i < _bb; i++)
#define rep3(i, a, b, c) for (ll i = a, _bb = b; (c > 0 && a <= i && i < _bb) or (c < 0 && a >= i && i > _bb); i += c)
#define rrep(i, a, b) for (ll i=(a); i>(b); i--)
#define pb push_back
#define eb emplace_back
#define mkp make_pair
#define ALL(A) begin(A), end(A)
#define UNIQUE(A) sort(ALL(A)), A.erase(unique(ALL(A)), A.end())
#define elif else if
#define tostr to_string
#ifndef CONSTANTS
constexpr ll INF = 1e18; constexpr int MOD = 1000000007; constexpr ld EPS = 1e-10; constexpr ld PI = M_PI;
#endif
template<typename T1, typename T2> istream &operator>>(istream &is, pair<T1, T2> &p) { is >> p.first >> p.second; return is; } template<typename T> istream &operator>>(istream &is, vector<T> &v) { for (T &in : v) is >> in; return is; } template<typename T = ll> vector<T> LIST(int N) { vector<T> A(N); rep(i, N) { cin >> A[i]; } return A; }
template<typename T> bool chmax(T &x, T y) { return (y > x) ? x = y, true : false; }
template<typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &p) { return os << p.first << ' ' << p.second; } template<class T, size_t... Is> void print_tuple(ostream &os, const T &arg, index_sequence<Is...>) { static_cast<void>(((os << (Is == 0 ? "" : " "), os << get<Is>(arg)), ...)); } template<class... Ts> ostream &operator<<(ostream &os, const tuple<Ts...> &arg) { print_tuple(os, arg, make_index_sequence<sizeof...(Ts)>()); return os; } template<typename T, size_t N> ostream &operator<<(ostream &os, const array<T, N> &arr) { rep(i, N) { os << arr[i]; if (i != (int)N - 1) { os << ' '; } } return os; } template<typename T, size_t N> void print(const array<T, N> &arr, string sep = " ") { rep(i, N) { cout << arr[i]; if (i != (int)N - 1) cout << sep; } cout << '\n'; } template<typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { rep(i, vec.size()) { os << vec[i]; if (i != (int)vec.size() - 1) { os << ' '; } } return os; } template<typename T> void print(const vector<T> &vec, string sep = " ") { rep(i, vec.size()) { cout << vec[i]; if (i != (int)vec.size() - 1) cout << sep; } cout << '\n'; } template<typename T> void print(const deque<T> &que, string sep = " ") { vector<T> vec(ALL(que)); print(vec, sep); } template<typename T> void print(const set<T> &se, string sep = " ") { vector<T> vec(ALL(se)); print(vec, sep); } template<typename T> void print(const initializer_list<T> &li, string sep = " ") { vector<T> V(ALL(li)); print(V, sep); } void print() { cout << '\n'; } template<typename T> void print(T out) { cout << out << '\n'; }
#define debug(...) multi_debug(#__VA_ARGS__, __VA_ARGS__)
template<typename T> void multi_debug(string name, const vv<T> &grid) { cerr << name << ":" << endl; int H = grid.size(); int W = grid[0].size(); vector<int> mxlen(W); rep(h, H) { rep(w, W) { chmax(mxlen[w], (int)tostr(grid[h][w]).size()); } } rep(h, H) { rep(w, W) { int pad = mxlen[w] - (int)tostr(grid[h][w]).size(); cerr << string(pad, ' ') << grid[h][w]; if (w == W - 1) { cerr << endl; } else { cerr << ' '; } } } } template<class Tp, class... Ts> void multi_debug(string names, Tp arg, Ts... args) { if constexpr (sizeof...(Ts) == 0) { while (names.back() == ' ') { names.pop_back(); } cerr << names << ": " << arg << endl; } else { int n = names.size(), comma_pos = -1, paren_depth = 0, inside_quote = false; rep(i, n) { if (not inside_quote and paren_depth == 0 and names[i] == ',') { comma_pos = i; break; } if (names[i] == '\"' or names[i] == '\'') { if (i > 0 and names[i - 1] == '\\') continue; inside_quote ^= true; } if (not inside_quote and names[i] == '(') { paren_depth++; } if (not inside_quote and names[i] == ')') { paren_depth--; } } assert(comma_pos != -1); string name = names.substr(0, comma_pos); while (name.back() == ' ') { name.pop_back(); } cerr << name << ": " << arg << endl; int next_begin_at = comma_pos + 1; while (names[next_begin_at] == ' ') { next_begin_at++; } names = names.substr(next_begin_at); multi_debug(names, args...); } } template<typename T> void print(const vector<T> &V, char sep) { print(V, string{sep}); } template<typename T, size_t N> void print(const array<T, N> &arr, char sep) { print(arr, string{sep}); }

namespace DynamicRerootingImpl {
template<typename Point, Point (*rake)(const Point &, const Point &)>
struct SplayTreeforDashedEdge {
    struct Node {
        Node *l, *r, *p;
        Point key, sum;

        explicit Node(const Point &_key)
            : l(nullptr),
              r(nullptr),
              p(nullptr),
              key(_key),
              sum(_key) {
        }
    };

    SplayTreeforDashedEdge() {
    }

    using NP = Node *;

    void rotr(NP t) {
        NP x = t->p, y = x->p;
        if ((x->l = t->r)) t->r->p = x;
        t->r = x, x->p = t;
        update(x), update(t);
        if ((t->p = y)) {
            if (y->l == x) y->l = t;
            if (y->r == x) y->r = t;
        }
    }

    void rotl(NP t) {
        NP x = t->p, y = x->p;
        if ((x->r = t->l)) t->l->p = x;
        t->l = x, x->p = t;
        update(x), update(t);
        if ((t->p = y)) {
            if (y->l == x) y->l = t;
            if (y->r == x) y->r = t;
        }
    }

    void update(NP t) {
        t->sum = t->key;
        if (t->l) t->sum = rake(t->sum, t->l->sum);
        if (t->r) t->sum = rake(t->sum, t->r->sum);
    }

    NP get_right(NP t) {
        while (t->r) t = t->r;
        return t;
    }

    NP alloc(const Point &v) {
        auto t = new Node(v);
        update(t);
        return t;
    }

    void splay(NP t) {
        while (t->p) {
            NP q = t->p;
            if (!q->p) {
                if (q->l == t) rotr(t);
                else rotl(t);
            } else {
                NP r = q->p;
                if (r->l == q) {
                    if (q->l == t) rotr(q), rotr(t);
                    else rotl(t), rotr(t);
                } else {
                    if (q->r == t) rotl(q), rotl(t);
                    else rotr(t), rotl(t);
                }
            }
        }
    }

    NP insert(NP t, const Point &v) {
        if (not t) {
            t = alloc(v);
            return t;
        } else {
            NP cur = get_right(t), z = alloc(v);
            splay(cur);
            z->p = cur;
            cur->r = z;
            update(cur);
            splay(z);
            return z;
        }
    }

    NP erase(NP t) {
        splay(t);
        NP x = t->l, y = t->r;
        delete t;
        if (not x) {
            t = y;
            if (t) t->p = nullptr;
        } else if (not y) {
            t = x;
            t->p = nullptr;
        } else {
            x->p = nullptr;
            t = get_right(x);
            splay(t);
            t->r = y;
            y->p = t;
            update(t);
        }
        return t;
    }
};

template<
    typename Path, typename Point, typename Info, Path (*vertex)(const Info &),
    Path (*compress)(const Path &, const Path &),
    Point (*rake)(const Point &, const Point &),
    Point (*add_edge)(const Path &),
    Path (*add_vertex)(const Point &, const Info &)>
struct TopTree {
private:
    struct Node {
        Node *l, *r, *p;
        Info info;
        Path key, sum, mus;
        typename SplayTreeforDashedEdge<Point, rake>::Node *light, *belong;
        bool rev;

        bool is_root() const {
            return not p or (p->l != this and p->r != this);
        }

        explicit Node(const Info _info)
            : l(nullptr),
              r(nullptr),
              p(nullptr),
              info(_info),
              light(nullptr),
              belong(nullptr),
              rev(false) {
        }
    };

public:
    using NP = Node *;
    SplayTreeforDashedEdge<Point, rake> splay_tree;

private:
    void toggle(NP t) {
        swap(t->l, t->r);
        swap(t->sum, t->mus);
        t->rev ^= true;
    }

    void rotr(NP t) {
        NP x = t->p, y = x->p;
        push(x), push(t);
        if ((x->l = t->r)) t->r->p = x;
        t->r = x, x->p = t;
        update(x), update(t);
        if ((t->p = y)) {
            if (y->l == x) y->l = t;
            if (y->r == x) y->r = t;
        }
    }

    void rotl(NP t) {
        NP x = t->p, y = x->p;
        push(x), push(t);
        if ((x->r = t->l)) t->l->p = x;
        t->l = x, x->p = t;
        update(x), update(t);
        if ((t->p = y)) {
            if (y->l == x) y->l = t;
            if (y->r == x) y->r = t;
        }
    }

public:
    TopTree() : splay_tree{} {
    }

    void push(NP t) {
        if (t->rev) {
            if (t->l) toggle(t->l);
            if (t->r) toggle(t->r);
            t->rev = false;
        }
    }

    void push_rev(NP t) {
        if (t->rev) {
            if (t->l) toggle(t->l);
            if (t->r) toggle(t->r);
            t->rev = false;
        }
    }

    void update(NP t) {
        Path key =
            t->light ? add_vertex(t->light->sum, t->info) : vertex(t->info);
        Path sum = key, mus = key;
        if (t->l)
            sum = compress(t->l->sum, sum), mus = compress(mus, t->l->mus);
        if (t->r)
            sum = compress(sum, t->r->sum), mus = compress(t->r->mus, mus);
        t->key = key, t->sum = sum, t->mus = mus;
    }

    void splay(NP t) {
        push(t);
        {
            NP rot = t;
            while (not rot->is_root()) rot = rot->p;
            t->belong = rot->belong;
            if (t != rot) rot->belong = nullptr;
        }
        while (not t->is_root()) {
            NP q = t->p;
            if (q->is_root()) {
                push_rev(q), push_rev(t);
                if (q->l == t) rotr(t);
                else rotl(t);
            } else {
                NP r = q->p;
                push_rev(r), push_rev(q), push_rev(t);
                if (r->l == q) {
                    if (q->l == t) rotr(q), rotr(t);
                    else rotl(t), rotr(t);
                } else {
                    if (q->r == t) rotl(q), rotl(t);
                    else rotr(t), rotl(t);
                }
            }
        }
    }

    NP expose(NP t) {
        NP rp = nullptr;
        for (NP cur = t; cur; cur = cur->p) {
            splay(cur);
            if (cur->r) {
                cur->light =
                    splay_tree.insert(cur->light, add_edge(cur->r->sum));
                cur->r->belong = cur->light;
            }
            cur->r = rp;
            if (cur->r) {
                splay_tree.splay(cur->r->belong);
                push(cur->r);
                cur->light = splay_tree.erase(cur->r->belong);
            }
            update(cur);
            rp = cur;
        }
        splay(t);
        return rp;
    }

    void link(NP child, NP parent) {
        expose(parent);
        expose(child);
        child->p = parent;
        parent->r = child;
        update(parent);
    }

    void cut(NP child) {
        expose(child);
        NP parent = child->l;
        child->l = nullptr;
        parent->p = nullptr;
        update(child);
    }

    void evert(NP t) {
        expose(t);
        toggle(t);
        push(t);
    }

    NP alloc(const Info &info) {
        NP t = new Node(info);
        update(t);
        return t;
    }

    bool is_connected(NP u, NP v) {
        expose(u), expose(v);
        return u == v or u->p;
    }

    NP lca(NP u, NP v) {
        if (not is_connected(u, v)) return nullptr;
        expose(u);
        return expose(v);
    }

    void set_key(NP t, const Info &v) {
        expose(t);
        t->info = v;
        update(t);
    }

    // u を根とする sum
    Path query(NP u) {
        evert(u);
        return u->sum;
    }

    // root を根, u を部分木の根とする sum
    Path query_subtree(NP root, NP u) {
        evert(root);
        expose(u);
        NP l = u->l;
        u->l = nullptr;
        update(u);
        auto ret = u->sum;
        u->l = l;
        update(u);
        return ret;
    }
};

template<
    typename Path, typename Point, typename Info, Path (*vertex)(const Info &),
    Path (*compress)(const Path &, const Path &),
    Point (*rake)(const Point &, const Point &),
    Point (*Add_edge)(const Path &),
    Path (*add_vertex)(const Point &, const Info &)>
struct DynamicRerooting {
    int n;
    TopTree<Path, Point, Info, vertex, compress, rake, Add_edge, add_vertex> tt;
    using NP = typename decltype(tt)::NP;
    vector<NP> vs;

    DynamicRerooting(int _n, const vector<Info> &info) : n(_n), vs(n) {
        for (int i = 0; i < n; i++) vs[i] = tt.alloc(info[i]);
    }
    // u-v 間に辺を追加
    void add_edge(int u, int v) {
        tt.evert(vs[u]);
        tt.link(vs[u], vs[v]);
    }
    // u-v 間の辺を削除
    void del_edge(int u, int v) {
        tt.evert(vs[u]);
        tt.cut(vs[v]);
    }
    // 頂点 u の情報を取得
    Info get_info(int u) {
        return vs[u]->info;
    }
    // 頂点 u の情報を設定
    void set_info(int u, const Info &info) {
        tt.set_key(vs[u], info);
    }
    // 頂点 u を根とするクエリ
    Path query(int u) {
        return tt.query(vs[u]);
    }
    // 頂点 root を根, 頂点 u を部分木の根とするクエリ
    Path query_subtree(int root, int u) {
        return tt.query_subtree(vs[root], vs[u]);
    }
};

} // namespace DynamicRerootingImpl

using DynamicRerootingImpl::DynamicRerooting;

// mx := 最遠点への距離
// p := その部分木の上の接点の頂点番号
// c := その部分木の下の接点の頂点番号
// mxi := その部分木の最遠点の頂点番号
// ptoc := 上下接点間の距離
struct Path {
    ll mx;
    int p, c, mxi;
    ll ptoc;
};
struct Point {
    ll mx;
    int mxi;
};
// struct Info {
// };
using Info = pair<ll, int>;
Path vertex(const Info &info) {
    auto [val, i] = info;
    Path res;
    res.mx = val;
    res.mxi = i;
    res.p = res.c = i;
    res.ptoc = val;
    return res;
}
Path compress(const Path &p, const Path &c) {
    Path res;
    // pの最遠点がcの上接点ならそのまま繋ぐ
    if (p.mxi == c.p) {
        res.mx = p.mx + c.mx;
        res.mxi = c.mxi;
    } else {
        // そうでなければ「pの最遠点」と「pの接点間+cの最遠点」を比較
        if (p.mx >= p.ptoc + c.mx) {
            res.mx = p.mx;
            res.mxi = p.mxi;
        } else {
            res.mx = p.ptoc + c.mx;
            res.mxi = c.mxi;
        }
    }
    res.p = p.p;
    res.c = c.c;
    res.ptoc = p.ptoc + c.ptoc;
    return res;
}
Point rake(const Point &a, const Point &b) {
    Point res;
    if (a.mx >= b.mx) {
        res.mx = a.mx;
        res.mxi = a.mxi;
    } else {
        res.mx = b.mx;
        res.mxi = b.mxi;
    }
    return res;
}
Point add_edge(const Path &a) {
    Point res;
    res.mx = a.mx;
    res.mxi = a.mxi;
    return res;
}
Path add_vertex(const Point &a, const Info &info) {
    auto [val, i] = info;
    Path res;
    res.mx = {a.mx + val};
    res.mxi = i;
    res.p = res.c = i;
    res.ptoc = val;
    return res;
}
using DRR = DynamicRerooting<Path, Point, Info, vertex, compress, rake, add_edge, add_vertex>;

void solve() {
    ll N;
    cin >> N;
    vector<Info> info(N * 2 - 1);
    vector<pii> edges;
    rep(u, N) {
        info[u] = {0, u};
    }
    rep(i, N - 1) {
        ll u, v, w;
        cin >> u >> v >> w;
        edges.eb(u, N + i);
        edges.eb(v, N + i);
        info[N + i] = {w, N + i};
    }
    DRR drr(N * 2 - 1, info);
    for (auto [u, v] : edges) {
        drr.add_edge(u, v);
    }

    rep(u, N) {
        ll res = drr.query(u).mx;
        print(res);
    }
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(15);

    // single test case
    solve();

    // multi test cases
    // int T;
    // cin >> T;
    // while (T--) solve();

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 8580
final_rank: 17

code_snippet: #include <cassert>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <deque>
#include <tuple>
#include <functional>
#include <optional>

using namespace std;

constexpr int INF = 1e9;

vector<int> dist(int r, const vector<vector<pair<int, int>>> &edges)
{
    vector<int> res(edges.size(), INF);
    res[r] = 0;

    set<pair<int, int>> breads{{0, r}};
    while (breads.size())
    {
        auto it = breads.begin();
        const auto [d, s] = *it;
        breads.erase(it);

        if (res[s] < d)
            continue;

        for (const auto &[w, t] : edges[s])
        {
            if (d + w < res[t])
            {
                res[t] = d + w;
                breads.emplace(d + w, t);
            }
        }
    }

    return res;
}

int main()
{
    int N;
    cin >> N;

    vector<vector<pair<int, int>>> edges(N);
    for (int i = 1; i < N; ++i)
    {
        int s, t, w;
        cin >> s >> t >> w;
        edges[s].push_back({w, t});
        edges[t].push_back({w, s});
    }

    const auto d0 = dist(0, edges);
    int max_i = -1;
    {
        int max_d = -1;
        for (int i = 0; i < N; ++i)
        {
            if (max_d < d0[i])
            {
                max_d = d0[i];
                max_i = i;
            }
        }
    }

    const auto d1 = dist(max_i, edges);
    max_i = -1;
    {
        int max_d = -1;
        for (int i = 0; i < N; ++i)
        {
            if (max_d < d1[i])
            {
                max_d = d1[i];
                max_i = i;
            }
        }
    }

    const auto d2 = dist(max_i, edges);

    for (int i = 0; i < N; ++i)
    {
        cout << max(d1[i], d2[i]) << endl;
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4440
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (long long i = 0; i < (long long)(n); i++)
#define rrep(i,start,end) for (long long i = start;i >= (long long)(end);i--)
#define repn(i,end) for(long long i = 0; i <= (long long)(end); i++)
#define reps(i,start,end) for(long long i = start; i < (long long)(end); i++)
#define repsn(i,start,end) for(long long i = start; i <= (long long)(end); i++)
#define each(p,a) for(auto &p:a)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<long long> vll;
typedef vector<pair<long long ,long long>> vpll;
typedef vector<vector<long long>> vvll;
typedef set<ll> sll;
typedef map<long long , long long> mpll;
typedef pair<long long ,long long> pll;
typedef tuple<long long , long long , long long> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (int)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1LL << 60;
const ld EPS = 1e-9;
 
inline ll lfloor(ll x,ll m){return (x - ((x % m+ m)%m))/m;}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;

//ref https://github.com/drken1215/algorithm/blob/master/Tree/rerooting_with_edge.cpp
//verify https://atcoder.jp/contests/abc348/submissions/52401893
template<class M,class E>
struct ReRooting{
  using Graph = vector<vector<E>>;
  using GetIdFunc = function<ll(E)>;//Eから辺の行き先を取り出す
  using AddEdgeFunc = function<M(E, M)>;//情報を持ち上げるときにやりたい操作
  using MergeFunc = function<M(M, M)>;//情報のマージ
  using AddNodeFunc = function<M(ll, M)>;//頂点の情報で反映させたいもの

  Graph g;
  M e;
  GetIdFunc getid;
  AddEdgeFunc addedge;
  MergeFunc merge;
  AddNodeFunc addnode;

  vector<vector<M>> dp;

  ReRooting(){}
  ReRooting(const Graph &_g,const M &_e,const GetIdFunc &_getid,const AddEdgeFunc &_addedge,const MergeFunc &_merge,const AddNodeFunc &_addnode){
    g = _g;
    e = _e;
    getid = _getid;
    addedge = _addedge;
    merge = _merge;
    addnode = _addnode;
    build();
  }

  //木DPする
  M rooting(ll v,ll par){
    M ret = e;
    dp[v].assign((ll)g[v].size(),e);
    rep(i,g[v].size()){
      ll nv = getid(g[v][i]);
      if(nv == par)continue;
      dp[v][i] = rooting(nv,v);
      ret = merge(ret,addedge(g[v][i],dp[v][i]));
    }
    return addnode(v,ret);
  }

  void rerooting(ll v,ll par,M pval){
    rep(i,g[v].size()){
      ll nv = getid(g[v][i]);
      if(nv == par){
        dp[v][i] = pval;//親から来たやつ
        continue;
      }
    }
    //左右累積計算
    vector<M> left(g[v].size() + 1,e);
    vector<M> right(g[v].size() + 1,e);
    rep(i,g[v].size()){
      ll ri = (ll)g[v].size() -1- i;
      left[i+1] = merge(left[i],addedge(g[v][i],dp[v][i]));
      right[i+1] = merge(right[i],addedge(g[v][ri],dp[v][ri]));
    }
    rep(i,g[v].size()){
      ll nv = getid(g[v][i]);
      ll ri = (ll) g[v].size()- 1 - i;
      if(nv == par)continue;
      M npval = merge(left[i],right[ri]);
      rerooting(nv,v,addnode(v,npval));
    }
  }

  void build(){
    dp.assign((ll)g.size(),vector<M>());
    ll root = 0;
    rooting(root,-1);  
    
    rerooting(root,-1,e);
  }

  M get(ll x){
    M ret = e;
    rep(i,g[x].size()){
      ret = merge(ret,addedge(g[x][i],dp[x][i]));
    }
    return addnode(x,ret);
  }
};

 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  LL(n);
  vector<vpll> g(n);
  rep(i,n-1){
    LL(a,b,w);
    g[a].push_back({b,w});
    g[b].push_back({a,w});  
  }

  using M = ll;
  using E = pll;
  auto getid = [&](E x){
    return x.first;
  };
  auto addedge = [&](E a,M b)-> M{
    return a.second + b;
  };
  auto merge = [&](M a,M b)-> M{
    return max(a,b);
  };
  auto addnode = [&](ll a,M b)->M{
    return b;
  };
  M e = 0;
  ReRooting<M,E> rr(g,e,getid,addedge,merge,addnode);
  rr.build();

  rep(i,n){
   cout << rr.get(i) << endl;
  }




}
accuracy: 1
time_ms: 10
memory_kb: 7980
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=int64_t;
  
vector<vector<tuple<int,int,int>>> g(10000);

int dfs(int x,int p){
  if((g[x].size()==1)&&(p!=-1)){
    return get<1>(g[x][0]);
  }
  int mx=0,mp=0;
  for(int i=0;i<(int)g[x].size();i++){
    if(get<0>(g[x][i])==p){ 
      mp=get<1>(g[x][i]);
      continue;
    }
    if(get<2>(g[x][i])!=-1){
      mx=max(mx,get<2>(g[x][i]));
    }else{
      get<2>(g[x][i])=dfs(get<0>(g[x][i]),x);
      mx=max(mx,get<2>(g[x][i]));
     // cout << x << "-" << get<0>(g[x][i]) << " " << mx << endl;
    }
  }
  return mx+mp;
}

int main(){
  int n;
  cin >> n;
  if(n==1){
    cout << 0 << endl;
    return 0;
  }
  
  int s,t,w;
  for(int i=0;i<n-1;i++){
    cin >> s >> t >> w;
    g[s].emplace_back(t,w,-1);
    g[t].emplace_back(s,w,-1);
  }
  for(int i=0;i<n;i++){
    int ans=dfs(i,-1);
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 100
memory_kb: 4532
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<ll, ll>;
#define rep(i, a, b) for(ll i = a; i < b; ++i)
#define rrep(i, a, b) for(ll i = a; i >= b; --i)
constexpr ll inf = 4e18;
struct SetupIO {
    SetupIO() {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout << fixed << setprecision(30);
    }
} setup_io;
template <typename T = int>
struct Edge {
    int from, to;
    T cost;
    int idx;
    Edge()
        : from(-1), to(-1), cost(-1), idx(-1) {}
    Edge(int from, int to, T cost = 1, int idx = -1)
        : from(from), to(to), cost(cost), idx(idx) {}
    operator int() const {
        return to;
    }
};
template <typename T = int>
struct Graph {
    vector<vector<Edge<T>>> g;
    int es;
    Graph(int n)
        : g(n), es(0) {}
    size_t size() const {
        return g.size();
    }
    void add_edge(int from, int to, T cost = 1) {
        g[from].emplace_back(from, to, cost, es);
        g[to].emplace_back(to, from, cost, es++);
    }
    void add_directed_edge(int from, int to, T cost = 1) {
        g[from].emplace_back(from, to, cost, es++);
    }
    inline vector<Edge<T>>& operator[](const int& k) {
        return g[k];
    }
    inline const vector<Edge<T>>& operator[](const int& k) const {
        return g[k];
    }
};
template <typename T = int>
using Edges = vector<Edge<T>>;
template <typename DP, typename T, typename F1, typename F2>
vector<DP> rerooting(const Graph<T>& g, const F1& f1, const F2& f2, const DP& id) {
    const int n = (int)g.size();
    vector<DP> memo(n, id), dp(n, id);
    auto dfs = [&](auto& dfs, int cur, int par) -> void {
        for(const auto& e : g[cur]) {
            if(e.to == par) continue;
            dfs(dfs, e, cur);
            memo[cur] = f1(memo[cur], f2(memo[e.to], e.to, cur));
        }
    };
    auto efs = [&](auto& efs, int cur, int par, const DP& pval) -> void {
        vector<DP> buf;
        for(const auto& e : g[cur]) {
            if(e.to == par) continue;
            buf.push_back(f2(memo[e.to], e.to, cur));
        }
        vector<T> head(buf.size() + 1), tail(buf.size() + 1);
        head[0] = tail[buf.size()] = id;
        for(int i = 0; i < (int)buf.size(); ++i) head[i + 1] = f1(head[i], buf[i]);
        for(int i = (int)buf.size() - 1; i >= 0; --i) {
            tail[i] = f1(tail[i + 1], buf[i]);
        }
        dp[cur] = par == -1 ? head.back() : f1(pval, head.back());
        int idx = 0;
        for(const auto& e : g[cur]) {
            if(e.to == par) continue;
            efs(efs, e.to, cur, f2(f1(pval, f1(head[idx], tail[idx + 1])), cur, e));
            ++idx;
        }
    };
    dfs(dfs, 0, -1);
    efs(efs, 0, -1, id);
    return dp;
}
int main(void) {
    int n;
    cin >> n;
    Graph<int> g(n);
    map<pair<int, int>, int> mp;
    rep(i, 0, n - 1) {
        int a, b, c;
        cin >> a >> b >> c;
        g.add_edge(a, b, c);
        mp[{a, b}] = c;
        mp[{b, a}] = c;
    }
    using DP = int;
    auto f1 = [&](DP x, DP y) -> DP {
        return max(x, y);
    };
    auto f2 = [&](DP x, int child, int parent) -> DP {
        return x + mp[{child, parent}];
    };
    DP id = 0;
    vector<DP> dp = rerooting(g, f1, f2, id);
    rep(i, 0, n) {
        cout << dp[i] << '\n';
    }
}
accuracy: 1
time_ms: 10
memory_kb: 8076
final_rank: 16

code_snippet: #include <bits/stdc++.h>
// #include <atcoder/all>
#if __has_include(<boost/algorithm/string.hpp>)
#include <boost/algorithm/string.hpp>
#endif
#if __has_include(<boost/algorithm/cxx11/all_of.hpp>)
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/algorithm/cxx11/any_of.hpp>
#include <boost/algorithm/cxx11/none_of.hpp>
#include <boost/algorithm/cxx11/one_of.hpp>
#endif
#if __has_include(<boost/lambda/lambda.hpp>)
#include <boost/lambda/lambda.hpp>
#endif
#if __has_include(<boost/range/irange.hpp>)
#include <boost/range/irange.hpp>
#include <boost/range/adaptors.hpp>
#endif
#if __has_include(<boost/multiprecision/cpp_int.hpp>)
#include <boost/multiprecision/cpp_int.hpp>
#endif
#if __has_include(<gmpxx.h>)
#include <gmpxx.h>
#endif

using namespace std;

// constant values
const int INF32 = numeric_limits<int>::max(); //2.147483647×10^{9}:32bit整数のinf
const int inf32 = INF32 / 2;
const long long INF64 = numeric_limits<long long>::max(); //9.223372036854775807×10^{18}:64bit整数のinf
const long long inf64 = INF64 / 2;
const double EPS = numeric_limits<double>::epsilon(); //問題による
// const int MOD = 998244353; //問題による

bool DEBUG = true;

// REP macro
#define OVERLOAD_REP(_1, _2, _3, name, ...) name
#define REP1(i, n) REP2(i, 0, n)
#define REP2(i, l, r) for (long long (i) = (l); (i) < (long long)(r); ++(i))
#define REP3(i, l, r, s) for (long long (i) = (l); (i) < (long long)(r); (i) += (s))
#define rep(i, ...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(i, __VA_ARGS__)

#define REPD1(i, n) REPD2(i, 0, n)
#define REPD2(i, l, r) for (long long (i) = (long long)(r) - 1; (i) >= (long long)(l); --(i))
#define REPD3(i, l, r, s) for (long long (i) = (long long)(r) - 1; (i) >= (long long)(l); (i) -= (s))
#define repd(i, ...) OVERLOAD_REP(__VA_ARGS__, REPD3, REPD2, REPD1)(i, __VA_ARGS__)

#define fore(i, I) for (auto& (i): (I))
#define fored(i, I) for (auto& (i): (I) | views::reverse)
#define all(A) A.begin(), A.end()

// for debug
#define debug(x) if (DEBUG) cerr << #x << ": " << x << endl;
#define debug_v(A) if (DEBUG) {cerr << #A << ": " << endl; fore(a, A) cerr << a << " "; cerr << endl;}
#define debug_vv(A) if (DEBUG) {cerr << #A << ": " << endl; fore(v, A) {fore(a, v) cerr << a << " "; cerr << endl;} cerr << endl;}

// 省略
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second

using ll = long long;
using ull = unsigned long long;
using vll = vector<ll>;
using setll = set<ll>;
using mapll = map<ll, ll>;
using pll = pair<ll, ll>;

template<typename T>
using vec = vector<T>;

template<typename T>
using vv = vector<vector<T>>;

template<typename T>
using vvv = vector<vector<vector<T>>>;

using str = string;
using vstr = vector<str>;
using sstr = set<str>;

using vchar = vector<char>;
using schar = set<char>;

using vd = vector<double>;

// boost関連
#if __has_include(<boost/algorithm/cxx11/all_of.hpp>)
using boost::algorithm::all_of_equal;
using boost::algorithm::any_of_equal;
using boost::algorithm::none_of_equal;
using boost::algorithm::one_of_equal;
using boost::algorithm::all_of;
using boost::algorithm::any_of;
using boost::algorithm::none_of;
using boost::algorithm::one_of;
#endif
#if __has_include(<boost/lambda/lambda.hpp>)
using boost::lambda::_1;
using boost::lambda::_2;
using boost::lambda::_3;
#endif
#if __has_include(<boost/multiprecision/cpp_int.hpp>)
using namespace boost::multiprecision;
using lll = int128_t;
#endif
#if __has_include(<gmpxx.h>)
#include <gmpxx.h>
using mpz = mpz_class;
#endif

template<typename T>
inline void input(T& a) {
    cin >> a;
}

template<typename T>
inline void input(T& a, T& b) {
    input(a); input(b);
}

template<typename T>
inline void input(T& a, T& b, T& c) {
    input(a); input(b, c);
}

template<typename T>
inline void input(T& a, T& b, T& c, T& d) {
    input(a); input(b, c, d);
}

template<typename T>
inline void input(T& a, T& b, T& c, T& d, T& e) {
    input(a); input(b, c, d, e);
}

template<typename T>
inline void input(T& a, T& b, T& c, T& d, T&e, T& f) {
    input(a); input(b, c, d, e, f);
}

template<typename T>
inline void input(vector<T>& A) {
    rep(i, A.size()) cin >> A.at(i);
}

template<typename T>
inline void input(vector<T>& A, vector<T>& B) {
    if (A.size() != B.size()) throw runtime_error("Vector sizes are different.");
    
    rep(i, A.size) {
        cin >> A.at(i) >> B.at(i);
    }
}

template<typename T>
inline void input(vector<T>& A, vector<T>& B, vector<T>& C) {
    if (A.size() != B.size() or A.size() != C.size()) throw runtime_error("Vector sizes are different.");
    
    rep(i, A.size) {
        cin >> A.at(i) >> B.at(i) >> C.at(i);
    }
}

template<typename T>
inline void input(const long long N, vector<T>& A) {
    rep(i, N) {
        T a;
        cin >> a;
        A.push_back(a);
    }
}

template<typename T>
inline void input(const long long N, vector<T>& A, vector<T>& B) {
    rep(i, N) {
        T a, b;
        cin >> a >> b;
        A.push_back(a);
        B.push_back(b);
    }
}

template<typename T>
inline void input(const long long N, vector<T>& A, vector<T>& B, vector<T>& C) {
    rep(i, N) {
        T a, b, c;
        cin >> a >> b >> c;
        A.push_back(a);
        B.push_back(b);
        C.push_back(c);
    }
}

template<typename T>
inline void input(const long long N, set<T>& A) {
    rep(i, N) {
        T a;
        cin >> a;
        A.insert(a);
    }
}

template<typename T>
inline void input(const long long N, set<T>& A, set<T>& B) {
    rep(i, N) {
        T a, b;
        cin >> a >> b;
        A.insert(a);
        B.insert(b);
    }
}

template<typename T>
inline void input(const long long N, set<T>& A, set<T>& B, set<T>& C) {
    rep(i, N) {
        T a, b, c;
        cin >> a >> b >> c;
        A.insert(a);
        B.insert(b);
        C.insert(c);
    }
}

template<typename T>
inline void input(const long long H, const long long W, vector<vector<T>>& A) {
    rep(i, H) {
        vector<T> v;
        rep(j, W) {
            T a;
            cin >> a;
            v.push_back(a);
        }
        
        A.push_back(v);
    }
}

// 第一引数と第二引数を比較し、第一引数(a)をより大きい/小さい値に上書き
template<typename T>
inline bool chmin(T &a, const T &b) {
    bool compare = a > b;
    if (compare) a = b;
    return compare;
}

template<typename T>
inline bool chmax(T &a, const T &b) {
    bool compare = a < b;
    if (compare) a = b;
    return compare;
}

template<class Weight = long long, class Cap = long long>
struct Edge {
    long long from;
    long long to;
    Weight weight;
    Cap cap;
    long long id;
    long long rev;
    Cap flow;
    
    explicit Edge(long long u = -1, long long v = -1, Weight w = 1, long long i = -1, Cap cap = 0, long long rev = -1) : from(u), to(v), weight(w), cap(cap), id(i), rev(rev), flow(0) {};

    bool operator < (const Edge& other) const {
        if (from == other.from) {
            if (to == other.to) return weight < other.weight;
            else return to < other.to;
        }
        else return from < other.from;
    }
};

struct Stamp {
    long long index;
    long long time;
    explicit Stamp(long long i = 0, long long t = -1) : index(i), time(t) {};

    bool operator<(const Stamp& right) const {
        return time < right.time;
    }
};

template<class Weight = long long, class Cap = long long, class DP = long long>
struct Graph {
    // DFS, BFS共通
    long long V;
    bool directed;
    vector<vector<Edge<Weight, Cap>>> G;
    vector<bool> seen, done;
    vector<Edge<Weight, Cap>> prev;
    long long edge_index = 0;
    vector<Edge<Weight, Cap>> edges;

    // DFS用
    vector<Stamp> pre_order, post_order;
    long long first, last;
    bool has_cycle;
    vector<long long> descendants;
    long long inf = inf64;

    // BFS用
    vector<long long> depth;

    // ダイクストラ用
    vector<Weight> cost;

    // LCA用
    vector<vector<long long>> doubling;
    long long log;
    bool _lca_init_done;

    // 二部グラフ用
    bool _is_bipartite = true;
    vector<long long> colors;

    // CC用
    vector<long long> groups;
    vector<set<long long>> cc; 
    vector<set<long long>> cc_edge;

    // SCC用
    vector<vector<Edge<Weight, Cap>>> rG;
    vector<long long> roots;
    vector<set<long long>> scc;

    // トポロジカルソート用
    vector<long long> topo_dp;

    // 全方位木dp用
    vector<vector<DP>> dp;
    vector<DP> prod_all;
    long long root;

    // maxflow用
    vector<long long> level;
    vector<long long> iter;

    // mincostflow用
    vector<Weight> dual, dist;
    vector<long long> prevv, preve;
    Cap cur_flow;
    Cap cur_cost, pre_cost;
    vector<pair<Cap, Weight>> min_cost_slope;

    explicit Graph(long long V, bool directed) : V(V), directed(directed), G(V), rG(V) {
        init();
    };
    
    void init() {
        first = 0;
        last = 0;
        has_cycle = false;
        _lca_init_done = false;
        cur_flow = 0;
        cur_cost = 0;
        pre_cost = -1;

        log = 1;
        while ((1ll << log) <= V) log++;

        seen.assign(V, false);
        done.assign(V, false);
        prev.assign(V, Edge<Weight, Cap>());
        colors.assign(V, -1);
        descendants.assign(V, 0);
        roots.assign(V, -1);
        groups.assign(V, -1);
        depth.assign(V, inf);
        cost.assign(V, inf);
        doubling.assign(log, vector<long long>(V, -1));
        level.assign(V, -1);
        iter.assign(V, 0);
        dual.assign(V, 0);
        dist.assign(V, 0);
        prevv.assign(V, -1);
        preve.assign(V, -1);
        topo_dp.assign(V, 0);
        dp.resize(V);
        prod_all.assign(V, id());
    }
    
    void connect(long long from, long long to, Weight weight = 1) {
        assert(0 <= from and from < V);
        assert(0 <= to and to < V);

        if (directed) {
            edges.emplace_back(from, to, weight, edge_index);

            G.at(from).emplace_back(from, to, weight, edge_index);
            rG.at(to).emplace_back(to, from, weight, edge_index);
        }
        else {
            long long from_id = G.at(from).size();
            long long to_id = G.at(to).size();

            edges.emplace_back(from, to, weight, edge_index, weight, from_id);

            G.at(from).emplace_back(from, to, weight, edge_index, weight, to_id);
            G.at(to).emplace_back(to, from, weight, edge_index, 0, from_id);

            dp.at(from).push_back(id());
            dp.at(to).push_back(id());
        }

        edge_index++;
    }

    void connect(long long from, long long to, Cap cap, Weight cost) {
        assert(0 <= from and from < V);
        assert(0 <= to and to < V);

        if (!directed) {
            long long from_id = G.at(from).size();
            long long to_id = G.at(to).size();

            edges.emplace_back(from, to, cost, edge_index, cap, from_id);

            G.at(from).emplace_back(from, to, cost, edge_index, cap, to_id);
            G.at(to).emplace_back(to, from, -cost, edge_index, 0, from_id);
        }

        edge_index++;
    }

    DP id() {
        return 0;
    }

    DP merge(DP x, DP y) {
        return max(x, y);
    }

    DP put_edge(DP x, Edge<Weight, Cap>& edge) {
        return x + (DP)edge.weight;
    }

    DP put_vertex(DP x, long long v) {
        return x;
    }

    DP build(long long root_) {
        root = root_;
        return dfs(root);
    }

    vector<DP> reroot() {
        dfs_dp(root, id());

        return prod_all;
    }

    void dfs_all() {
        long long group = 0;

        rep(i, V) {
            if (seen.at(i)) continue;
            dfs(i, group);
            group++;
        }
    }

    DP dfs(long long now, long long group = 0, Edge<Weight, Cap> e = Edge<Weight, Cap>()) {
        assert(0 <= now and now < V);

        DP ret = id();

        seen.at(now) = true;
        pre_order.emplace_back(now, first);
        first++;

        groups.at(now) = group;
        while (cc.size() <= group) cc.push_back(set<long long>());
        cc.at(group).insert(now);
        while (cc_edge.size() <= group) cc_edge.push_back(set<long long>());

        if (colors.at(now) == -1) colors.at(now) = 0;
        long long next_color = !colors.at(now);

        rep(i, G.at(now).size()) {
            Edge<Weight, Cap> edge = G.at(now).at(i);
            long long next = edge.to;

            if (edge.id == e.id) continue;

            cc_edge.at(group).insert(edge.id);

            if (colors.at(next) == -1) colors.at(next) = next_color;
            else if (colors.at(next) != next_color) _is_bipartite = false;

            if (seen.at(next)) {
                if (!done.at(next)) has_cycle = true;
                continue;
            }

            prev.at(next) = edge;

            dp.at(now).at(i) = dfs(next, group, edge);
            ret = merge(ret, put_edge(dp.at(now).at(i), edge));

            descendants.at(now) += descendants.at(next) + 1;
        }

        done.at(now) = true;
        post_order.emplace_back(now, last);
        last++;

        return put_vertex(ret, now);
    }

    void dfs_dp(long long now, const DP& dp_p, Edge<Weight, Cap> e = Edge<Weight, Cap>()) {
        long long deg = G.at(now).size();

        if (e.rev != -1) dp.at(now).at(e.rev) = dp_p;

        vector<DP> prod_l(deg + 1, id()), prod_r(deg + 1, id());

        rep(i, deg) {
            Edge<Weight, Cap> edge = G.at(now).at(i);
            prod_l.at(i + 1) = merge(prod_l.at(i), put_edge(dp.at(now).at(i), edge));
        }

        repd(i, deg) {
            Edge<Weight, Cap> edge = G.at(now).at(i);
            prod_r.at(i) = merge(prod_r.at(i + 1), put_edge(dp.at(now).at(i), edge));
        }

        prod_all.at(now) = put_vertex(prod_l.back(), now);

        rep(i, deg) {
            if (i == e.rev) continue;

            Edge<Weight, Cap> edge = G.at(now).at(i);
            long long child = edge.to;
            dfs_dp(child, put_vertex(merge(prod_l.at(i), prod_r.at(i + 1)), now), edge);
        }
    }
    
    void dfs_scc(long long now, long long group) {  // SCC用
        roots.at(now) = group;
        fore(edge, rG.at(now)) {
            long long next = edge.to;
            if (roots.at(next) != -1) continue;
            dfs(next, group);
        }
    }

    Cap dfs_flow(long long v, long long s, long long t, Cap flow) { // maxflow用
        if (v == s) return flow;

        Cap res = 0;
        long long level_v = level.at(v);

        for (long long& i = iter.at(v); i < (long long)(G.at(v).size()); i++) {
            Edge<Weight, Cap>& e = G.at(v).at(i);
            long long next = e.to;

            if (level_v <= level.at(next) || G.at(next).at(e.rev).cap == 0) continue;

            Cap d = dfs_flow(next, s, t, min(flow - res, G.at(next).at(e.rev).cap));

            if (d <= 0) continue;

            G.at(v).at(i).cap += d;
            G.at(next).at(e.rev).cap -= d;
            res += d;

            if (res == flow) return res;
        }

        level.at(v) = V;
        return res;
    }

    void bfs_all() {
        long long group = 0;

        rep(i, V) {
            if (seen.at(i)) continue;
            bfs(i, group);
            group++;
        }
    }

    void bfs(long long start, long long group = -1) {
        assert(0 <= start and start < V);

        queue<long long> que;

        // 初期条件 (頂点 start を初期ノードとする)
        seen.at(start) = true;
        depth.at(start) = 0;
        groups.at(start) = group;
        que.push(start); // noq を橙色頂点にする

        // BFS 開始 (キューが空になるまで探索を行う)
        while (!que.empty()) {
            long long now = que.front(); // キューから先頭頂点を取り出す
            que.pop();

            // v から辿れる頂点をすべて調べる
            fore(edge, G.at(now)) {
                long long next = edge.to;
                if (seen.at(next)) continue; // すでに発見済みの頂点は探索しない
                seen.at(next) = true;

                // 新たな白色頂点 nv について距離情報を更新してキューに追加する
                depth.at(next) = depth.at(now) + 1;
                prev.at(next) = edge;
                groups.at(next) = group;
                que.push(next);
                doubling.front().at(next) = now;
            }
        }
    }

    void bfs_flow(long long s, long long t) {
        assert(0 <= s and s < V);
        assert(0 <= t and t < V);

        fill(level.begin(), level.end(), -1);
        queue<long long> que;

        // 初期条件 (頂点 start を初期ノードとする)
        level.at(s) = 0;
        que.push(s); // noq を橙色頂点にする

        // BFS 開始 (キューが空になるまで探索を行う)
        while (!que.empty()) {
            long long now = que.front(); // キューから先頭頂点を取り出す
            que.pop();

            // v から辿れる頂点をすべて調べる
            fore(edge, G.at(now)) {
                long long next = edge.to;
                if (edge.cap == 0 or level.at(next) >= 0) continue; // すでに発見済みの頂点は探索しない

                // 新たな白色頂点 nv について距離情報を更新してキューに追加する
                level.at(next) = level.at(now) + 1;
                
                if (next == t) return;
                que.push(next);
            }
        }
    }

    void lca_init(long long root) {
        assert(0 <= root and root < V);

        bfs(root);

        rep(k, log - 1) {
            rep(v, V) {
                if (doubling.at(k).at(v) >= 0) {
                    doubling.at(k + 1).at(v) = doubling.at(k).at(doubling.at(k).at(v));
                }
            }
        }

        _lca_init_done = true;
    }

    // lca_init後にuとvの最小共通祖先を返す
    long long lca(long long u, long long v) {
        assert(_lca_init_done);
        assert(0 <= u and u < V);
        assert(0 <= v and v < V);

        if (depth.at(u) < depth.at(v)) swap(u, v);

        rep(k, log) {
            if ((depth.at(u) - depth.at(v)) >> k & 1) {
                u = doubling.at(k).at(u);
            }
        }

        if (u == v) return u;
        
        repd(k, log - 1) {
            if (doubling.at(k).at(u) != doubling.at(k).at(v)) {
                u = doubling.at(k).at(u);
                v = doubling.at(k).at(v);
            }
        }

        return doubling.at(0).at(u);
    }

    // lca_init後にuとvの距離を返す
    long long get_dist(long long u, long long v) {
        assert(_lca_init_done);
        assert(0 <= u and u < V);
        assert(0 <= v and v < V);

        return depth.at(u) + depth.at(v) - 2 * depth.at(lca(u, v));
    }

    // lca_init後にuとvを結ぶパス上にaがあるか返す
    bool is_on_path(long long u, long long v, long long a) {
        assert(0 <= u and u < V);
        assert(0 <= v and v < V);
        assert(0 <= a and a < V);
        assert(_lca_init_done);

        return get_dist(u, a) + get_dist(a, v) == get_dist(u, v);
    }

    void dijkstra_all() {
        long long group = 0;

        rep(i, V) {
            if (done.at(i)) continue;
            dijkstra(i, group);
            group++;
        }
    }

    void dijkstra(long long start, long long group = -1) {
        assert(0 <= start and start < V);

        using pll = pair<long long, long long>;
        priority_queue<pll, vector<pll>, greater<>> que;

        cost.at(start) = 0;
        que.emplace(cost.at(start), start);
        while (!que.empty()) {
            long long now = que.top().second;
            que.pop();

            if (done.at(now)) continue;  // nowが確定済だったら飛ばす
            done.at(now) = true;   // nowを初めてキューから取り出したら最小として確定

            fore(edge, G.at(now)) {
                long long next = edge.to;
                if (chmin(cost.at(next), cost.at(now) + edge.weight)) {
                    prev.at(next) = edge;
                    que.emplace(cost.at(next), next);
                }
            }
        }
    }

    long long find_diameter() {
        long long ret = 0;

        rep(i, V) {
            if (seen.at(i)) continue;
            bfs(i);
            long long u = distance(depth.begin(), max_element(depth.begin(), depth.end()));

            init();
            bfs(u);
            long long v = distance(depth.begin(), max_element(depth.begin(), depth.end()));
            
            chmax(ret, depth.at(v));
            init();
        }

        return ret;
    }

    bool reach_at(long long to) {
        assert(0 <= to and to < V);

        return seen.at(to);
    }

    bool is_connected() {
        bool ret = true;
        rep(i, V) {
            if (seen.at(i)) continue;
            ret = false;
            break;
        }

        return ret;
    }

    vector<long long> path_to(long long to) {
        assert(0 <= to and to < V);

        vector<long long> p;
        p.push_back(to);

        while (prev.at(p.back()).from != -1) {
            p.push_back(prev.at(p.back()).from);
        }

        reverse(p.begin(), p.end());

        return p;
    }

    long long find_scc() {    // 強連結成分分解, 有効グラフで互いに行き来可能な頂点同士を調べる
        vector<long long> v = topological_sort();
        fore(index, v) {
            if (roots.at(index) != -1) continue;
            dfs_scc(index, index);
        }

        map<long long, set<long long>> m;

        rep(i, roots.size()) {
            m[roots.at(i)].insert(i);
        }

        fore(p, m) {
            set<long long> s_i = p.second;
            scc.push_back(s_i);
        }

        return (long long)scc.size();
    }

    vector<long long> topological_sort() {
        rep(i, V) sort(G.at(i).begin(), G.at(i).end());

        dfs_all();

        vector<long long> v;
        rep(i, V) v.push_back(post_order.at(i).index);
        reverse(v.begin(), v.end());

        return v;
    }

    bool is_same(long long u, long long v) {    // SCC用, 同じ強連結成分のグループかどうか返す
        assert(0 <= u and u < V);
        assert(0 <= v and v < V);
        
        return roots.at(u) == roots.at(v);
    }

    long long longest_path() {
        vector<long long> topo = topological_sort();

        init();

        rep(i, V) {
            ll now = topo.at(i);

            fore(edge, G.at(now)) {
                long long next = edge.to;

                if (chmax(topo_dp.at(next), topo_dp.at(now) + 1)) {
                    prev.at(next) = edge;
                }
            }
        }

        return *max_element(topo_dp.begin(), topo_dp.end());
    }

    vector<long long> get_longest_path() {
        vector<long long> ret;

        ll goal = dist(topo_dp.begin(), max_element(topo_dp.begin(), topo_dp.end()));

        return path_to(goal);
    }

    Cap max_flow(long long s, long long t) {
        return max_flow(s, t, numeric_limits<Cap>::max());
    }

    Cap max_flow(long long s, long long t, Cap flow_limit) {
        assert(0 <= s && s < V);
        assert(0 <= t && t < V);
        assert(s != t);

        Cap flow = 0;
        while (flow < flow_limit) {
            bfs_flow(s, t);

            if (level.at(s) == -1) break;

            fill(iter.begin(), iter.end(), 0);

            Cap f = dfs_flow(t, s, t, flow_limit - flow);

            if (!f) break;
            flow += f;
        }
        return flow;
    }

    void change_edge(long long i, Cap new_cap, Cap new_flow) {
        long long m = edges.size();

        assert(0 <= i && i < m);
        assert(0 <= new_flow && new_flow <= new_cap);

        Edge<Weight, Cap> edge = edges.at(i);

        auto& _e = G.at(edge.from).at(edge.rev);
        auto& _re = G.at(_e.to).at(_e.rev);
        _e.cap = new_cap - new_flow;
        _re.cap = new_flow;
    }

    // max_flow(s, t)後に使用することでs,t間の最小カットを返す
    vector<bool> min_cut(long long s) {
        vector<bool> visited(V);

        queue<long long> que;
        que.push(s);
        
        while (!que.empty()) {
            long long p = que.front();
            que.pop();
            visited.at(p) = true;

            fore(e, G.at(p)) {
                if (e.cap && !visited.at(e.to)) {
                    visited.at(e.to) = true;
                    que.push(e.to);
                }
            }
        }
        return visited;
    }

    pair<Cap, Weight> min_cost_flow(long long s, long long t) {
        return min_cost_flow(s, t, numeric_limits<Cap>::max());
    }
    
    pair<Cap, Weight> min_cost_flow(long long s, long long t, Cap flow_limit) {
        return slope(s, t, flow_limit).back();
    }

    vector<pair<Cap, Weight>> slope(long long s, long long t) {
        return slope(s, t, numeric_limits<Cap>::max());
    }

    vector<pair<Cap, Weight>> slope(long long s, long long t, Cap flow_limit) {
        assert(0 <= s && s < V);
        assert(0 <= t && t < V);
        assert(s != t);

        min_cost_slope.emplace_back(cur_flow, cur_cost);
        
        // primal-dual
        while (cur_flow < flow_limit) {
            if (!dual_step(s, t)) break;
            primal_step(s, t, flow_limit);
        }
        return min_cost_slope;
    }

    bool dual_step(long long s, long long t) {
        priority_queue<pair<Weight, long long>, vector<pair<Weight, long long>>, greater<pair<Weight, long long>>> que;
        que.emplace(0, s);

        dist.assign(G.size(), numeric_limits<Weight>::max());
        dist.at(s) = 0;

        while (!que.empty()) {
            auto p = que.top();
            auto cur_cost = p.first;
            auto v = p.second;
            que.pop();

            if (dist.at(v) < cur_cost) continue;
            rep(i, G.at(v).size()) {
                const auto &e = G.at(v).at(i);
                Weight new_cost = e.weight + dual.at(v) - dual.at(e.to);

                if (e.cap > 0 && dist.at(e.to) > dist.at(v) + new_cost) {
                    dist.at(e.to) = dist.at(v) + new_cost;
                    prevv.at(e.to) = v;
                    preve.at(e.to) = i;
                    que.emplace(dist.at(e.to), e.to);
                }
            }
        }
        
        if (dist.at(t) == numeric_limits<Weight>::max()) return false;
        
        rep(v, G.size()) {
            if (dist.at(t) == numeric_limits<Weight>::max()) continue;
            dual.at(v) -= dist.at(t) - dist.at(v);
        }
        return true;
    }

    void primal_step(long long s, long long t, Cap flow_limit) {
        Cap flow = flow_limit - cur_flow;
        Weight cost = -dual.at(s);
        for (long long v = t; v != s; v = prevv.at(v)) {
            flow = min(flow, G.at(prevv.at(v)).at(preve.at(v)).cap);
        }

        for (long long v = t; v != s; v = prevv.at(v)) {
            auto &e = G.at(prevv.at(v)).at(preve.at(v));
            auto &re = G.at(e.to).at(e.rev);
            e.cap -= flow, e.flow += flow;
            re.cap += flow, re.flow -= flow;
        }

        cur_flow += flow;
        cur_cost += flow * cost;

        if (pre_cost == cost) min_cost_slope.pop_back();
        min_cost_slope.emplace_back(cur_flow, cur_cost);
        pre_cost = cur_cost;
    }
};

int main() {
    long long N;
    input(N);

    Graph graph(N, false);

    rep(i, N - 1) {
        long long s, t, w;
        input(s, t, w);

        graph.connect(s, t, w);
    }

    graph.build(0);
    // debug_vv(graph.dp);
    vector<long long> dp = graph.reroot();
    // debug_vv(graph.dp);
    // debug_v(dp);
    fore(ans, dp) cout << ans << endl;

    // cout << fixed << setprecision(10);  // 小数点以下を10桁表示，許容誤差が1e-N以下の時はN+1に変更すること(16桁以上はlong double)
    // cout << ans << endl;
    // cout << YesNo(ans) << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 13196
final_rank: 19