# BZOJ1767/Gym207383I CEOI2009 Harbingers 斜率优化、可持久化单调栈、二分

$dep_x$表示$x$在树上的带权深度，$parent_x$表示$x$的祖先节点集合，$f_x$表示点$x$的答案

$f_x = \min\limits_{i \in parent_x}\{f_i + V_x \times (dep_x - dep_i)\} + S_x = \min\limits_{i \in parent_x}\{- dep_i \times V_x + f_i\} + S_x + V_x \times dep_x$

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#define int long long
#define mid ((l + r) >> 1)
#define lch Tree[x].l
#define rch Tree[x].r
//This code is written by Itst
using namespace std;

int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == '-')
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
}

const int MAXN = 1e5 + 7;
struct Edge{
int end , upEd , w;
}Ed[MAXN << 1];
struct line{
int k , b;
line(int _k = 0 , int _b = 0):k(_k) , b(_b){}
};
struct node{
int l , r;
line L;
}Tree[MAXN * 30];
int rt[MAXN] , head[MAXN] , ans[MAXN] , dep[MAXN] , V[MAXN] , S[MAXN] , cnt[MAXN];
int cntN , cntEd , N , maxN;

inline void addEd(int a , int b , int c){
Ed[++cntEd].end = b;
Ed[cntEd].w = c;
}

inline int calc(line l , int x){
return l.k * x + l.b;
}

line getL(int x , int l , int r , int tar){
if(l == r)
return Tree[x].L;
if(mid >= tar)
return getL(lch , l , mid , tar);
return getL(rch , mid + 1 , r , tar);
}

void ins(int &x , int l , int r , int tar , line L){
int t = ++cntN;
Tree[t] = Tree[x];
x = t;
if(l == r){
Tree[t].L = L;
return;
}
if(mid >= tar)
ins(lch , l , mid , tar , L);
else
ins(rch , mid + 1 , r , tar , L);
}

inline int erf(int id , int x){
int L = 1 , R = cnt[id];
while(L < R){
int MID = (L + R) >> 1;
if(calc(getL(rt[id] , 1 , N , MID) , x) > calc(getL(rt[id] , 1 , N , MID + 1) , x))
L = MID + 1;
else
R = MID;
}
return calc(getL(rt[id] , 1 , N , L) , x);
}

inline bool ifpop(line L1 , line L2 , line L3){
return (long double)(L1.b - L2.b) * (L3.k - L1.k) >= (long double)(L1.b - L3.b) * (L2.k - L1.k);
}

inline int erf2(int id , line l){
int L = 1 , R = cnt[id];
while(L < R){
int MID = (L + R) >> 1;
if(ifpop(getL(rt[id] , 1 , N , MID) , getL(rt[id] , 1 , N , MID + 1) , l))
R = MID;
else
L = MID + 1;
}
return L;
}

void dfs(int x , int p){
bool f = 1;
if(x != 1){
rt[x] = rt[p];
cnt[x] = cnt[p];
ans[x] = erf(x , V[x]) + dep[x] * V[x] + S[x];
line p = getL(rt[x] , 1 , N , cnt[x]);
if(p.k == -dep[x])
if(p.b > ans[x])
--cnt[x];
else
f = 0;
if(f)
cnt[x] = erf2(x , line(-dep[x] , ans[x]));
}
if(f)
ins(rt[x] , 1 , N , ++cnt[x] , line(-dep[x] , ans[x]));
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != p){
dep[Ed[i].end] = dep[x] + Ed[i].w;
dfs(Ed[i].end , x);
}
}

signed main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
for(int i = 1 ; i < N ; ++i){
int a = read() , b = read() , c = read();
addEd(a , b , c);
addEd(b , a , c);
}
for(int i = 2 ; i <= N ; ++i){