题目描述
题目解法
这道题的
d
p
dp
dp 式子是很容易列的,即
d
p
u
=
m
i
n
{
a
u
∗
b
v
+
d
p
v
}
dp_u=min\{a_u*b_v+dp_v\}
dpu=min{au∗bv+dpv},其中
v
v
v 在
u
u
u 的子树中
可以发现转移式子是一个一次函数的形式,可以想到用李超线段树维护
考虑一个较为暴力的做法:
对于每个
u
u
u,暴力加入每一个
v
v
v,即
b
v
b_v
bv 为斜率,
d
p
v
dp_v
dpv 为截距,
a
u
a_u
au 为自变量,每条一次函数的范围是无限的
这是可以用李超线段树维护的
这里需要注意
a
u
a_u
au 可能为负数,所以需要把
a
a
a 加上一个偏移量,使
a
a
a 数组为正数,在计算函数值时在减回来
发现上述做法可以用线段树合并来替代
即先合并儿子,在计算答案,在加入当前点
时间复杂度
O
(
n
l
o
g
n
)
O(n\;logn)
O(nlogn)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N(200100),M(200100),Del(100000);
int n,tans,a[N],b[N],dp[N];
int e[M],ne[M],h[N],idx;
int root[N],seg[N*20],lc[N*20],rc[N*20];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void add(int x,int y){
e[idx]=y,ne[idx]=h[x],h[x]=idx++;
}
int comp(int id1,int id2,int p){
if(!id1||!id2) return id1|id2;
int v1=b[id1]*(p-Del)+dp[id1];
int v2=b[id2]*(p-Del)+dp[id2];
return v1<v2?id1:id2;
}
void modify(int p,int l,int r,int id){
if(!seg[p]){ seg[p]=id;return;}
if(l==r){ seg[p]=comp(seg[p],id,l);return;}
int mid=(l+r)>>1;
if(comp(seg[p],id,mid)==id) swap(seg[p],id);
int lp=comp(seg[p],id,l),rp=comp(seg[p],id,r);
if(rp==id){
if(!rc[p]) rc[p]=++idx;
modify(rc[p],mid+1,r,id);
}
if(lp==id){
if(!lc[p]) lc[p]=++idx;
modify(lc[p],l,mid,id);
}
}
int merge(int p,int q,int l,int r){
if(!p||!q) return p|q;
int mid=(l+r)>>1;
if(l==r) return p;
lc[p]=merge(lc[p],lc[q],l,mid);
rc[p]=merge(rc[p],rc[q],mid+1,r);
modify(p,l,r,seg[q]);
return p;
}
void query(int p,int l,int r,int pos){
tans=comp(tans,seg[p],pos);
if(l==r) return;
int mid=(l+r)>>1;
if(mid>=pos&&lc[p]) query(lc[p],l,mid,pos);
if(mid<pos&&rc[p]) query(rc[p],mid+1,r,pos);
}
void dfs(int u,int fa){
root[u]=++idx;
bool isleaf=0;
for(int i=h[u];~i;i=ne[i]){
int v=e[i];
if(v==fa) continue;
isleaf=1,dfs(v,u);
root[u]=merge(root[u],root[v],1,N-1);
}
if(isleaf){
tans=seg[root[u]];
query(root[u],1,N-1,a[u]);
dp[u]=b[tans]*(a[u]-Del)+dp[tans];
}
modify(root[u],1,N-1,u);
}
signed main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read(),a[i]+=Del;
for(int i=1;i<=n;i++) b[i]=read();
memset(h,-1,sizeof(h));
for(int i=1,x,y;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
dfs(1,-1);
for(int i=1;i<=n;i++) printf("%lld ",dp[i]);
return 0;
}