题解
考虑两条路径 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an, b 1 , b 2 , … , b m b_1,b_2,\dots,b_m b1,b2,…,bm 如何合并,不妨设方向为 a 1 → b m a_1 \to b_m a1→bm,那么显然 b 1 → b m b_1 \to b_m b1→bm 部分的答案不变,记为 s u m b sum_b sumb, a 1 → a n a_1 \to a_n a1→an 的答案则需要考虑 { b m } \{b_m\} {bm} 的影响,即从 ∑ i = 1 n ( n − i + 1 ) × a i \sum_{i=1}^n (n-i+1) \times a_i ∑i=1n(n−i+1)×ai 变为 ∑ i = 1 n ( n − i + 1 ) × a i + m × a i \sum_{i=1}^n (n-i+1) \times a_i+m \times a_i ∑i=1n(n−i+1)×ai+m×ai ,记 ∑ a i = s a \sum a_i=s_a ∑ai=sa,则合并后路径的答案为 s u m b + s u m a + m × s a sum_b+sum_a+m \times s_a sumb+suma+m×sa,所以我们考虑点分治,用李超线段树求出 ( m , s u m b ) (m,sum_b) (m,sumb) 时的最大值即可。
注意路径有顺序,还要反着做一遍。
代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read(){
int k=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')k=k*10+c-'0',c=getchar();
return k*f;
}
const int N=1e5+10;
const LL MAXN=1e12;
int n,a[N];
int tot,ver[N<<1],fst[N],nxt[N<<1];
inline void add(int x,int y){ver[++tot]=y;nxt[tot]=fst[x];fst[x]=tot;}
struct Node{
LL k,b;
}t[N<<6];
inline double F(Node f,double x){return 1.0*f.k*x+f.b;}
int lc[N<<6],rc[N<<6],vt[N<<6],now,root;
int sz[N],v[N],rsy,rt,mn;
queue<int> q;
int lin[N],lt;
LL ans;
void change(int &p,LL l,LL r,Node x){
if(!p)p=++now;
if(!vt[p]){
vt[p]=1;
t[p]=x;
return;
}
LL l1=F(t[p],l),l2=F(x,l);
LL r1=F(t[p],r),r2=F(x,r);
if(l2>l1&&r2>r1){
t[p]=x;
return;
}
if(l2<l1&&r2<r1)return;
if(l==r)return;
LL mid=(l+r)>>1;
if(F(t[p],1.0*(l+r)/2)<F(x,1.0*(l+r)/2))swap(t[p],x);
if(t[p].k>x.k)change(lc[p],l,mid,x);
else change(rc[p],mid+1,r,x);
}
LL query(int p,LL l,LL r,LL x){
if(!vt[p])return 0;
LL s1=F(t[p],x),s2;
LL mid=(l+r)>>1;
if(x<=mid)s2=query(lc[p],l,mid,x);
else s2=query(rc[p],mid+1,r,x);
return max(s1,s2);
}
void dfs_pre(int x,int fa){
rsy++;
for(int i=fst[x];i;i=nxt[i]){
int y=ver[i];if(v[y]||y==fa)continue;
dfs_pre(y,x);
}
}
void dfs_get(int x,int fa){
sz[x]=1;int s=0;
for(int i=fst[x];i;i=nxt[i]){
int y=ver[i];if(y==fa||v[y])continue;
dfs_get(y,x);
sz[x]+=sz[y];
s=max(s,sz[y]);
}
s=max(s,rsy-sz[x]);
if(s<mn)mn=s,rt=x;
}
void dfs_s(int x,int fa,int dep,LL s1,LL s2,LL s){
ans=max(ans,s1);ans=max(ans,s2);
for(int i=fst[x];i;i=nxt[i]){
int y=ver[i];if(y==fa||v[y])continue;
dfs_s(y,x,dep+1,s1+1ll*a[y]*(dep+1),s2+s+a[y],s+a[y]);
}
}
void dfs_ans(int x,int fa,int dep,LL s1,LL s){
// cout<<"dfs_ans "<<x<<" "<<dep<<" "<<s1<<" "<<s<<" "<<query(1,1,MAXN,s)<<endl;
ans=max(ans,query(1,1,MAXN,s)+s1);
for(int i=fst[x];i;i=nxt[i]){
int y=ver[i];if(y==fa||v[y])continue;
dfs_ans(y,x,dep+1,1ll*a[y]*(dep+1)+s1,s+a[y]);
}
}
void dfs_jia(int x,int fa,int dep,LL s2,LL s){
change(root,1,MAXN,(Node){dep,s2});
for(int i=fst[x];i;i=nxt[i]){
int y=ver[i];if(y==fa||v[y])continue;
dfs_jia(y,x,dep+1,s2+s+a[y],s+a[y]);
}
}
void cl(int p,LL l,LL r){
t[p]=(Node){0,0};vt[p]=0;
if(l==r)return;
LL mid=(l+r)>>1;
if(lc[p])cl(lc[p],l,mid);
if(rc[p])cl(rc[p],mid+1,r);
lc[p]=rc[p]=0;
}
int summ=0;
inline void prework(){
q.push(1);
while(q.size()){
int x=q.front();q.pop();
rsy=rt=0;mn=1e9;
dfs_pre(x,x);dfs_get(x,x);
v[rt]=1;lt=0;
// cout<<"Rt "<<rt<<" "<<ans<<endl;
dfs_s(rt,rt,1,a[rt],a[rt],a[rt]);
for(int i=fst[rt];i;i=nxt[i]){
int y=ver[i];if(v[y])continue;
lin[++lt]=y;
// cout<<"Lin "<<rt<<" "<<y<<endl;
}
for(int i=1;i<=lt;++i){
int y=lin[i];
dfs_ans(y,rt,1,a[y],a[y]);dfs_jia(y,rt,2,a[rt]*2+a[y],a[rt]+a[y]);
}
cl(1,1,MAXN);now=0;root=0;
for(int i=lt;i;--i){
int y=lin[i];
dfs_ans(y,rt,1,a[y],a[y]);dfs_jia(y,rt,2,a[rt]*2+a[y],a[rt]+a[y]);
}
cl(1,1,MAXN);now=0;root=0;
for(int i=1;i<=lt;++i)q.push(lin[i]);
}
printf("%lld\n",ans);
}
int main(){
// freopen("sum1.in","r",stdin);
n=read();
for(int i=1;i<n;++i){
int x=read(),y=read();
add(x,y);add(y,x);
}
for(int i=1;i<=n;++i)a[i]=read();
prework();
return 0;
}