题目

展开
题目描述
You are given a tree with nn nodes (numbered from 11 to nn ) rooted at node 11 . Also, each node has two values associated with it. The values for ii -th node are a_{i}a
i

and b_{i}b
i

.

You can jump from a node to any node in its subtree. The cost of one jump from node xx to node yy is the product of a_{x}a
x

and b_{y}b
y

. The total cost of a path formed by one or more jumps is sum of costs of individual jumps. For every node, calculate the minimum total cost to reach any leaf from that node. Pay attention, that root can never be leaf, even if it has degree 11 .

Note that you cannot jump from a node to itself.

输入格式
The first line of input contains an integer nn ( 2<=n<=10^{5}2<=n<=10
5
) — the number of nodes in the tree.

The second line contains nn space-separated integers a_{1},a_{2},…,a_{n}(-10{5}<=a_{i}<=10{5})a
1

,a
2

,…,a
n

(−10
5
<=a
i

<=10
5
) .

The third line contains nn space-separated integers b_{1},b_{2},…,b_{n}(-10{5}<=b_{i}<=10{5})b
1

,b
2

,…,b
n

(−10
5
<=b
i

<=10
5
) .

Next n-1n−1 lines contains two space-separated integers u_{i}u
i

and v_{i}v
i

( 1<=u_{i},v_{i}<=n1<=u
i

,v
i

<=n ) describing edge between nodes u_{i}u
i

and v_{i}v
i

in the tree.

输出格式
Output nn space-separated integers, ii -th of which denotes the minimum cost of a path from node ii to reach any leaf.

题意翻译
有一颗n个节点的树(节点从1到n依次编号).每个节点有两个权值,第i个节点的权值为a_i,b_ia
i

,b
i

.

你可以从一个节点跳到它的任意一个子节点上.从节点xx跳到节点yy一次的花费为a_x\times b_ya
x

×b
y

.跳跃多次走过一条路径的总费用为每次跳跃的费用之和.请分别计算出每个节点到达树的每个叶子节点的费用中的最小值.

注意:就算树的深度为1,根节点也不算做叶子节点.另外,不能从一个节点跳到它自己.

输入格式:

第一行为一个整数n(2<=n<=10^5)n(2<=n<=10
5
)

第二行有n个整数a_1,a_2,…,a_n(-105<=a_i<=105)a
1

,a
2

,…,a
n

(−10
5
<=a
i

<=10
5
)

第三行有n个整数b_1,b_2,…,b_n(-105<=b_i<=105)b
1

,b
2

,…,b
n

(−10
5
<=b
i

<=10
5
)

接下来的n-1n−1行每行有2个整数u_i,v_iu
i

,v
i

, 表示节点u_i,v_iu
i

,v
i

间有一条边.

输出格式:

输出nn个空格隔开的整数,第ii个整数表示第ii个节点到每个叶节点花费中的最小值.

输入输出样例
输入 #1复制
3
2 10 -1
7 -7 5
2 3
2 1
输出 #1复制
10 50 0
输入 #2复制
4
5 -10 5 7
-8 -80 -3 -10
2 1
2 4
1 3
输出 #2复制
-300 100 0 0
说明/提示
In the first example, node 33 is already a leaf, so the cost is 00 . For node 22 , jump to node 33 with cost a_{2}×b_{3}=50a
2

×b
3

=50 . For node 11 , jump directly to node 33 with cost a_{1}×b_{3}=10a
1

×b
3

=10 .

In the second example, node 33 and node 44 are leaves, so the cost is 00 . For node 22 , jump to node 44 with cost a_{2}×b_{4}=100a
2

×b
4

=100 . For node 11 , jump to node 22 with cost a_{1}×b_{2}=-400a
1

×b
2

=−400 followed by a jump from 22 to 44 with cost a_{2}×b_{4}=100a
2

×b
4

=100 .

思路

朴素的 d p dp dp d p u = min ⁡ { d p v + a u × b v } [ v ∈ s u b t r e e ( u ) ] dp_u = \min\{dp_v + a_u \times b_v\} [v \in subtree(u)] dpu=min{dpv+au×bv}[vsubtree(u)]
然后我们发现这个是一个 k x + b kx + b kx+b 的形式,也就是 b v ( a u ) + d p v b_v(a_u) + dp_v bv(au)+dpv ,所以需要的是一个子树信息,子树信息能想到什么?线段树合并?dsu on tree?启发式合并?感觉都能做。
然后的话这里选择了线段树合并,至于朴素的线段树合并,线段树合并的复杂度是 n log ⁡ n n \log n nlogn 的,证明的话,就考虑 f ( a + b ) = f ( a ) + f ( b ) + s z ( a ⋂ b ) f(a + b) = f(a) + f(b) + sz(a \bigcap b) f(a+b)=f(a)+f(b)+sz(ab) 容易发现这边 s z ( a ⋂ b ) sz(a \bigcap b) sz(ab) 不会超过 min ⁡ { a , b } \min\{a,b\} min{a,b} 然后证明就很显然了,但是对于李超树合并,需要做的一点是,这个信息不可加,不可减,不可简单合并,所以要把 a ⋂ b a \bigcap b ab 的部分直接插到树上,复杂度是 n log ⁡ 2 n n \log^2 n nlog2n

代码

#include<cstdio>
#include<climits>
typedef long long ll;
const ll inf=LLONG_MAX;
const int infL=-1e5,infR=1e5,N=3e5+5;
int tot=0,num=0,cnt=0;
ll b[N],k[N],res[N];
int a[N],c[N];
int h[N],to[600005],ver[600005];
int rt[N],sonL[5000005],sonR[5000005],tag[5000005];
int read() {
    int x=0,f=1;char s=getchar();
    while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();}
    while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();}
    return x*f;
}
void add(int x,int y) {to[++cnt]=y;ver[cnt]=h[x];h[x]=cnt;}
ll min(ll x,ll y) {return x<y? x:y;}
ll calc(ll x,int id) {return k[id]*x+b[id];}
void change(int &p,int l,int r,int id) {
    if(!p) {tag[p=++tot]=id;return;}
    if(l==r) {
        if(calc(l,id)<calc(l,tag[p])) tag[p]=id;
        return;
    }
    int mid=l+r>>1;
    if(k[id]<k[tag[p]]) {
        if(calc(mid,id)<=calc(mid,tag[p])) {change(sonL[p],l,mid,tag[p]);tag[p]=id;}
        else {change(sonR[p],mid+1,r,id);}
    }
    else if(k[id]>k[tag[p]]) {
        if(calc(mid,id)<=calc(mid,tag[p])) {change(sonR[p],mid+1,r,tag[p]);tag[p]=id;}
        else {change(sonL[p],l,mid,id);}
    }
    else if(b[id]<b[tag[p]]) {
        tag[p]=id;
        return;
    }
}
ll ask(int p,int l,int r,int x) {
    if(!p) return inf;
    if(l==r) return calc(l,tag[p]);
    int mid=l+r>>1;
    ll minn=calc(x,tag[p]);
    if(x<=mid) return min(minn,ask(sonL[p],l,mid,x));
    else return min(minn,ask(sonR[p],mid+1,r,x));
}
int merge(int x,int y,int l,int r) {
    if(!x||!y) return x+y;
    if(l==r) return calc(l,tag[x])>calc(l,tag[y])? y:x;
    int mid=l+r>>1;
    sonL[x]=merge(sonL[x],sonL[y],l,mid);
    sonR[x]=merge(sonR[x],sonR[y],mid+1,r);
    change(x,l,r,tag[y]);
    return x;
}
void dfs(int x,int fa) {
    int du=0;
    for(int i=h[x]; i; i=ver[i]) {
        int y=to[i];
        if(y==fa) continue;
        dfs(y,x);++du;
        rt[x]=merge(rt[x],rt[y],infL,infR);
    }
    k[++num]=c[x];
    if(du) res[x]=b[num]=ask(rt[x],infL,infR,a[x]); 
    else res[x]=b[num]=0;
    change(rt[x],infL,infR,num);
}
signed main() {
    int n=read();
    for(int i=1; i<=n;++i) a[i]=read();
    for(int i=1; i<=n;++i) c[i]=read();
    for(int i=1; i<n;++i) {int x=read(),y=read();add(x,y);add(y,x);}
    dfs(1,-1);
    for(int i=1; i<=n;++i) printf("%lld ",res[i]);
    return 0;
}