// library begin: "lib/template.hpp" #ifdef TEMPLATE #else #define TEMPLATE # pragma GCC optimize("O3") #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace ryoku{} using uint=unsigned; using ll=long long; using ull=unsigned long long; using ld=long double; using pii=pair; using pll=pair; using i128=__int128; using u128=unsigned __int128; templateusing vc=vector; templateusing vvc=vc>; templateusing vvvc=vvc>; templateusing smpq=priority_queue,greater>; templateusing bipq=priority_queue; #define rep(i,n) for(ll i=0;i<(ll)(n);i++) #define REP(i,j,n) for(ll i=(j);i<(ll)(n);i++) #define DREP(i,n,m) for(ll i=(n);i>=(m);i--) #define drep(i,n) for(ll i=((n)-1);i>=0;i--) #define rall(x) x.rbegin(),x.rend() #define mp(...) make_pair(__VA_ARGS__) #define pb push_back #define fi first #define se second #define is insert #define bg begin() #define ed end() #define all(x) x.begin(),x.end() void scan(int&a) { cin >> a; } void scan(ll&a) { cin >> a; } void scan(string&a) { cin >> a; } void scan(char&a) { cin >> a; } void scan(uint&a) { cin >> a; } void scan(ull&a) { cin >> a; } void scan(bool&a) { cin >> a; } void scan(ld&a){ cin>> a;} template void scan(vector&a) { for(auto&x:a) scan(x); } void read() {} template void read(Head&head, Tail&... tail) { scan(head); read(tail...); } #define INT(...) int __VA_ARGS__; read(__VA_ARGS__); #define LL(...) ll __VA_ARGS__; read(__VA_ARGS__); #define ULL(...) ull __VA_ARGS__; read(__VA_ARGS__); #define STR(...) string __VA_ARGS__; read(__VA_ARGS__); #define VC(type, name, ...) vector name(__VA_ARGS__); read(name); #define VVC(type, name, size, ...) vector> name(size, vector(__VA_ARGS__)); read(name); templatevoid print(T a) { cout << a; } template void print(vectora) { for(int i=0;i<(int)a.size();i++){if(i)cout<<" ";print(a[i]);}} void PRT() { cout < void PRT(T a) { print(a); cout < void PRT(Head head, Tail ... tail) { print(head); cout << " "; PRT(tail...); return; } template bool chmin(T &x, F y){ if(x>y){ x=y; return true; } return false; } template bool chmax(T &x, F y){ if(x T floor(T a,T b){ return a/b-(a%b&&((a<0)!=(b<0))); } template T ceil(T a,T b){ return a/b+(a%b&&((a<0)==(b<0))); } template T bmod(T x,T y){ return x-y*floor(x,y); } template pairdivmod(T x,T y){ T q=floor(x,y); return{q,x-q*y}; } void YesNo(bool b){ cout<<(b?"Yes":"No")<stovi(const string&s,const string&S){ vcv(s.size()); rep(i,s.size()){ auto t=S.find(s[i]); assert(t!=string::npos); v[i]=t; } return v; } template T isqrt(T x){ T F=sqrtl(x); while((F+1)*(F+1)<=x)F++; while(F*F>x)F--; return F; } template T tri(T x){return x*(x-1)/2;} //[l,r) templateT tri(T l,T r){return (r-l)*(l+r-1)/2;} //n を先頭に持ってくる template vcrot(vcv,int n){ rotate(v.begin(),v.begin()+n,v.end()); return v; } template auto rle(const Container&cv){ using T=typename Container::value_type; vc>res; for(const auto&x:cv){ if(res.empty()||res.back().fi!=x)res.pb({x,1}); else res.back().se++; } return res; } template vciota(int n){ vcv(n);rep(i,n)v[i]=i; return v; } template vcargsort(const vc&a){ auto idx=iota(a.size()); sort(all(idx),[&](int i,int j){ return (minfirst?make_pair(a[i],i)make_pair(a[j],j)); }); return idx; } template vvctrans(const vvc&a){ assert(a.size()&&a[0].size()); rep(i,a.size())assert(a[i].size()==a[0].size()); vvcb(a[0].size(),vc(a.size())); rep(i,a.size())rep(j,a[0].size())b[j][i]=a[i][j]; return b; } vctrans(const vc&a){ assert(a.size()&&a[0].size()); rep(i,a.size())assert(a[i].size()==a[0].size()); vcb(a[0].size(),string(a.size(),0)); rep(i,a.size())rep(j,a[0].size())b[j][i]=a[i][j]; return b; } template int popcount(T n){ return __builtin_popcountll(n); } template L sum(const vc&a){ return accumulate(all(a),L(0)); } template struct subset_view{ T s; struct iterator{ T s,x; bool done; T operator*()const{return x;} iterator&operator++(){ if(x==0)done=true; else x=(x-1)&s; return*this; } bool operator!=(const iterator&r)const{return done!=r.done;} }; iterator begin()const{return{s,s,false};} iterator end()const{return{s,0,true};} }; template subset_viewsubset(T s){ return{s}; } template T max(vc&a){ return *max_element(all(a)); } template T min(vc&a){ return *min_element(all(a)); } template vc presum(vc &a){ vc ret(a.size()+1); rep(i,a.size())ret[i+1]=ret[i]+a[i]; return ret; } template vc &operator+=(vc &a,F b){ for (auto&v:a)v += b; return a; } template vc &operator-=(vc&a,F b){ for (auto&v:a)v-=b; return a; } template vc &operator*=(vc&a,F b){ for (auto&v:a)v*=b; return a; } template constexpr T pow(T a,T b){ T res=1; while(b){ if(b&1)res*=a; a*=a; b/=2; } return res; } constexpr ll ten(ll a){ return pow(10,a); } templateconstexpr T inf=numeric_limits::max()/2-1; template<> constexpr pll inf ={inf,inf}; template constexpr T neg_inf=-inf; template<> constexpr pll neg_inf ={-inf,-inf}; template int tbit(T x){ using U=make_unsigned_t; U y=(U)x; return y?(int)bit_width(y)-1:-1; } template int lbit(T x){ using U=make_unsigned_t; U y=(U)x; return y?(int)countr_zero(y):-1; } template int tbit(T x,int p){ using U=make_unsigned_t; constexpr int W=numeric_limits::digits; U y=(U)x; if(p<0)return -1; if(p>=W-1)return tbit(y); return tbit(y&((U(1)<<(p+1))-1)); } template int lbit(T x,int p){ using U=make_unsigned_t; constexpr int W=numeric_limits::digits; U y=(U)x; if(p<0)return lbit(y); if(p>=W)return -1; return lbit(y&(~U(0)<>(istream&is,i128&x){ string s;is>>s; x=0; int i=0,neg=0; if(s[0]=='-')neg=1,i=1; for(;i<(int)s.size();i++)x=x*10+s[i]-'0'; if(neg)x=-x; return is; } ostream& operator<<(ostream&os,i128 x){ if(x==0)return os<<0; if(x<0)os<<"-"; u128 y=x<0?-(u128)x:(u128)x; string s; while(y)s.pb('0'+y%10),y/=10; reverse(all(s)); return os<sync_with_stdio(0); #ifdef LOCAL cout< struct edge{ int from,to,id; [[no_unique_address]]T cost; #ifdef LOCAL friend ostream&operator<<(ostream&os,const edge&e){ return os<<"{from:"< struct static_graph{ constexpr static bool directed(){return is_directed;} using edge=::ryoku::edge; using cost_t=T; private: int n; mutable bool built=false,inv_built=false; vcedges; mutable vcstart,inv_start; mutable vccsr,inv_csr; public: static_graph(int n):n(n),start(n+1),inv_start(n+1){assert(n>=0);} static_graph(int n,int m):static_graph(n){assert(m>=0);edges.reserve(m);} void resize(int size){ assert(n<=size&&!built); assert(!inv_built); n=size; start.resize(n+1); inv_start.resize(n+1); } void add_edge(const edge&e){ assert(!built&&!inv_built); assert(0<=e.from&&e.from void input(int m){ assert(m>=0); rep(i,m){ INT(a,b); a-=substract;b-=substract; add_edge(a,b); } build(); } void build()const{ if(built)return; built=true; start.assign(n+1,0); for(auto&e:edges){ ++start[e.from]; if constexpr(!is_directed)++start[e.to]; } rep(i,n)start[i+1]+=start[i]; csr.resize(start[n]); for(auto it=edges.rbegin();it!=edges.rend();++it){ auto&e=*it; csr[--start[e.from]]=e; if constexpr(!is_directed)csr[--start[e.to]]={e.to,e.from,e.id,e.cost}; } } void buildinv()const{ if(inv_built)return; inv_start.assign(n+1,0); for(auto&e:edges){ ++inv_start[e.to]; if constexpr(!is_directed)++inv_start[e.from]; } rep(i,n)inv_start[i+1]+=inv_start[i]; inv_csr.resize(inv_start[n]); for(auto it=edges.rbegin();it!=edges.rend();++it){ auto&e=*it; inv_csr[--inv_start[e.to]]={e.to,e.from,e.id,e.cost}; if constexpr(!is_directed)inv_csr[--inv_start[e.from]]={e.from,e.to,e.id,e.cost}; } inv_built=true; } auto operator[](int u){ build(); assert(0<=u&&u(csr.data()+start[u],start[u+1]-start[u]); } auto operator[](int u)const{ build(); assert(0<=u&&u(csr.data()+start[u],start[u+1]-start[u]); } auto inv(int u){ buildinv(); assert(0<=u&&u(inv_csr.data()+inv_start[u],inv_start[u+1]-inv_start[u]); } auto inv(int u)const{ buildinv(); assert(0<=u&&u(inv_csr.data()+inv_start[u],inv_start[u+1]-inv_start[u]); } const vc&all_edges()const{return edges;} int edge_size()const{return edges.size();} edge get_edge(int id)const{ assert(0<=id&&id vvcadj()const{ vvcres(n,vc(n)); for(auto&e:edges){ res[e.from][e.to]=e.cost; if constexpr(!is_directed)res[e.to][e.from]=e.cost; } return res; } void clear(){ built=false; inv_built=false; edges.clear(); csr.clear(); inv_csr.clear(); start.assign(n+1,0); inv_start.assign(n+1,0); } template void sort(int i,F f){ build(); assert(0<=i&&i struct tree{ using Graph=static_graph<0,T>; using edge=typename Graph::edge; using cost_t=typename Graph::cost_t; mutable Graph g; mutable int built_hld=-1; int n; mutable vcin,out,head,size_,par,depth,ord,cp,cp_root; tree(int n):n(n),g(n,n-1){} void add_edge(const edge&e){ g.add_edge(e); } void add_edge(int a,int b,cost_t cost=1,int id=-1){ g.add_edge(a,b,cost,id); } bool is_to_par(auto&e)const{ return par[e.from]==e.to; } int size()const{ return n; } bool same(int a,int b)const{ assert(0<=a&&a void input(){ rep(i,n-1){ INT(a,b); a-=substract; b-=substract; g.add_edge(a,b); } } template void build(int root=0)const{ if(built_hld!=-1)return; assert(0<=root&&rootvoid{ cp[u]=c;depth[u]=d++; auto s=g[u]; int heavy=-1,par_id=-1,heavy_size=0; rep(i,s.size()){ auto&e=s[i]; if(e.to==v){par_id=i;continue;} par[e.to]=u; dfs(dfs,e.to,u,d,c); size_[u]+=size_[e.to]; if(size_[e.to]>heavy_size)heavy_size=size_[e.to],heavy=i; } if(heavy!=-1&&heavy!=0){ swap(s[heavy],s[0]); if(par_id==0)par_id=heavy; else if(par_id==heavy)par_id=0; } if(par_id!=-1&&par_id+1!=s.size())swap(s[par_id],s[s.size()-1]); }; auto visit=[&](int u){ int c=cp_root.size(); cp_root.pb(u);par[u]=-1;head[u]=u; dfs(dfs,u,-1,0,c); }; visit(root); rep(u,n)if(cp[u]==-1)visit(u); auto dfs2=[&](auto&dfs2,int u)->void{ in[u]=timer;ord[timer++]=u; auto s=g[u]; int ce=s.size()-(par[u]!=-1); if(ce){ head[s[0].to]=head[u]; dfs2(dfs2,s[0].to); REP(i,1,ce)head[s[i].to]=s[i].to,dfs2(dfs2,s[i].to); } if constexpr(disjoint)out[u]=timer++; else out[u]=timer; }; for(auto u:cp_root)dfs2(dfs2,u); } auto heavy_edge(int u)const{ assert(0<=u&&u{s.data(),s.data()}; return span{s.data(),s.data()+1}; } auto light_edges(int u)const{ assert(0<=u&&u{s.data(),s.data()}; return span{s.data()+1,s.data()+ce}; } int lca(int a,int b)const{ assert(0<=a&&a0){ int x=I[a]-I[H[a]]; if(x>=k){ return O[I[a]-k]; } k-=x+1; a=P[H[a]]; } return a; } int jump(int s,int t,int k)const{ assert(0<=s&&s=k){ return jumpup(s,k); }else{ return jumpup(t,D-k); } } int to(int x,int y)const{ assert(0<=x&&x>query(int s,int t,bool edge=false)const{ assert(0<=s&&s>rs,rt; while(h[s]!=h[t]){ if(d[h[s]]>d[h[t]]){ rs.push_back({I[s],I[h[s]]}); s=P[h[s]]; }else{ rt.push_back({I[h[t]],I[t]}); t=P[h[t]]; } } if(s!=t||!edge){ if(d[s]>d[t]){ rs.push_back({I[s],I[t]+edge}); }else{ rt.push_back({I[s]+edge,I[t]}); } } rs.reserve(rs.size()+rt.size()); for(auto it=rt.rbegin();it!=rt.rend();++it)rs.push_back(*it); return rs; } pairget_diameter(int v=0)const{ assert(n>0); assert(0<=v&&vint{ vcd(n),p(n,-2),st(1,from); p[from]=-1; int far=from; while(!st.empty()){ int u=st.back(); st.pop_back(); if(d[far],vc>get_explicit_path(int u,int v)const{ vcres; vces; auto dfs=[&](auto&dfs,int now,int pre)->int{ res.pb(now); if(now==v){ return 1; } for(auto&e:g[now]){ if(e.to==pre)continue; es.pb(e); if(dfs(dfs,e.to,now))return 1; es.pop_back(); } return 0; }; dfs(dfs,u,-1); return{res,es}; } }; } #ifdef LOCAL #include"lib/debug/formatters/tree--base.hpp" #endif // library end: "lib/tree/base.hpp" // library include: "lib/graph/base.hpp" using namespace ryoku; void solve(){ LL(n); VC(ll,a,n); VC(ll,b,n); treeg(n);g.input<1>(); auto dfs=[&](auto&dfs,int u,int v)->array{ arrayres{}; res[0]=0;res[1]=a[u]; for(auto&e:g[u]){ if(e.to==v)continue; auto rdp=dfs(dfs,e.to,u); arrayndp{-inf,-inf}; rep(use,2){ rep(pre,2){ dbg(res[pre],(1-use)*(1-pre)*(b[u]+b[e.to]),use,pre); chmax(ndp[use],res[use]+rdp[pre]+(1-use)*(1-pre)*(b[u]+b[e.to])); } } res=move(ndp); } dbg(res); return res; }; auto ans=dfs(dfs,0,-1); PRT(max(ans[0],ans[1])); } signed main(){ int t=1; // cin >> t; while(t--)solve(); }