感谢王队长对本题的点拨...
我们先直接以1为根,考虑到一个点的代价貌似只和根与儿子节点有关。所以想到状态f[],h[],分别表示父亲还没炸,炸掉i子树
的花费和父亲先被炸掉的花费,可以观察到h[i]<=f[i]恒成立。
TYPE A :
因为c[i] <= 1,所以说只存在h[i] = f[i]或者f[i] = h[i] + 1,然后我们考虑如果先炸了i,会给i的父亲节点提供0到1点贡献(可能c[i] = 0,也可能i的父亲已经被炸成0了。)所以当f[i] = h[i],用f[i]向上转移一定是最优的。然后考虑f[i] = h[i] + 1的情况,因为用f[i]不一定能提供一的贡献而h[i]一定能,所以此h[i]更优。所以就可以直接转移了。复杂度o(n),注意父亲节点被儿子节点炸下0后要和0取max。
TYPE B :
现在c[i] <= 5,先考虑节点u以及它的儿子节点v,如果d[u] > c[v]并且f[v] - h[v] < c[v],这个时候用f[v]转移比h[v]更优,同理当f[v] - h[v] >= c[v]时用h[v]更优,但是这样就完了吗?当然不是,考虑到如果很多节点都选择了f[v]来转移的话,d[u]说不定早就被减成负数了,如果d[u] < 0,此时明显应该是h[v]更优才对,所以先对所有的f[v] - h[v] < c[v]用f[v]转移,如果转移后d[u] < 0,考虑撤销一些f[v],撤销的过程就等于是给u加上c[v]点血从而少花f[v] - h[v]点代价,所以这就是一个背包问题了,在背包的过程可以进行优化,设置一个Limit,Limit等于当前所有用f[v]转移的点的c[v]之和,每新加进来一个点,才把背包上线Limit加上c[v],选取一个最优决策转移就可以了。(注意这里背包做完之后最优解不一定还满足d[u] < 0...).
我们先直接以1为根,考虑到一个点的代价貌似只和根与儿子节点有关。所以想到状态f[],h[],分别表示父亲还没炸,炸掉i子树
的花费和父亲先被炸掉的花费,可以观察到h[i]<=f[i]恒成立。
TYPE A :
因为c[i] <= 1,所以说只存在h[i] = f[i]或者f[i] = h[i] + 1,然后我们考虑如果先炸了i,会给i的父亲节点提供0到1点贡献(可能c[i] = 0,也可能i的父亲已经被炸成0了。)所以当f[i] = h[i],用f[i]向上转移一定是最优的。然后考虑f[i] = h[i] + 1的情况,因为用f[i]不一定能提供一的贡献而h[i]一定能,所以此h[i]更优。所以就可以直接转移了。复杂度o(n),注意父亲节点被儿子节点炸下0后要和0取max。
TYPE B :
现在c[i] <= 5,先考虑节点u以及它的儿子节点v,如果d[u] > c[v]并且f[v] - h[v] < c[v],这个时候用f[v]转移比h[v]更优,同理当f[v] - h[v] >= c[v]时用h[v]更优,但是这样就完了吗?当然不是,考虑到如果很多节点都选择了f[v]来转移的话,d[u]说不定早就被减成负数了,如果d[u] < 0,此时明显应该是h[v]更优才对,所以先对所有的f[v] - h[v] < c[v]用f[v]转移,如果转移后d[u] < 0,考虑撤销一些f[v],撤销的过程就等于是给u加上c[v]点血从而少花f[v] - h[v]点代价,所以这就是一个背包问题了,在背包的过程可以进行优化,设置一个Limit,Limit等于当前所有用f[v]转移的点的c[v]之和,每新加进来一个点,才把背包上线Limit加上c[v],选取一个最优决策转移就可以了。(注意这里背包做完之后最优解不一定还满足d[u] < 0...).
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>
using namespace std;
struct node {int to;int next;};node bian[200010];
int first[100010],size,f[100010],h[100010],g[1000010];
int father[100010],d[100010],c[100010],n,a,b,maxc;
void inser(int x,int y) {
size ++;
bian[size].to = y;
bian[size].next = first[x];
first[x] = size;
}
void dfs(int x,int Anc) {
father[x] = Anc;
int _d1 = d[x],_d2 = d[x] - c[father[x]],ret = 0;
for(int u = first[x];u;u = bian[u].next)
{
if(bian[u].to == Anc) continue;
dfs(bian[u].to,x);
if(f[bian[u].to] == h[bian[u].to])
{
_d1 -= c[bian[u].to];
_d2 -= c[bian[u].to];
ret += f[bian[u].to];
}
else ret += h[bian[u].to];
}
f[x] = ret + max(_d1,0);
h[x] = ret + max(_d2,0);
}
int getint() {
char c = 'd';
int ret = 0;
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar();
return ret;
}
void bfs(int x,int Anc) {
father[x] = Anc;
int _d1 = d[x],_d2 = d[x] - c[father[x]],ret = 0;
for(int u = first[x];u;u = bian[u].next)
{
if(bian[u].to == Anc) continue;
bfs(bian[u].to,x);
if(f[bian[u].to] - h[bian[u].to] < c[bian[u].to])
{
_d1 -= c[bian[u].to];
_d2 -= c[bian[u].to];
ret += f[bian[u].to];
}
else ret += h[bian[u].to];
}
if(_d1 < 0)
{
int _n = 0;g[0] = 0;
for(int u = first[x];u;u = bian[u].next)
{
if(bian[u].to == Anc) continue;
if(f[bian[u].to] - h[bian[u].to] >= c[bian[u].to]) continue;
for(int i = _n + 1;i <= _n + c[bian[u].to];i ++)
g[i] = 0;
_n = _n + c[bian[u].to];
int C = c[bian[u].to],D = f[bian[u].to] - h[bian[u].to];
for(int i = 0;i + C <= _n;i ++)
g[i + C] = ((g[i + C] > g[i] + D) ? g[i + C] : g[i] + D);
}
f[x] = ret;
for(int i = 1;i <= _n;i ++)
f[x] = min(f[x],max(0,_d1 + i) + ret - g[i]);
//f[x] = ret - g[_n];
}
else f[x] = ret + max(_d1,0);
if(_d2 < 0)
{
int _n = 0;g[0] = 0;
for(int u = first[x];u;u = bian[u].next)
{
if(bian[u].to == Anc) continue;
if(f[bian[u].to] - h[bian[u].to] >= c[bian[u].to]) continue;
for(int i = _n + 1;i <= _n + c[bian[u].to];i ++)
g[i] = 0;
_n = _n + c[bian[u].to];
int C = c[bian[u].to],D = f[bian[u].to] - h[bian[u].to];
for(int i = 0;i + C <= _n;i ++)
g[i + C] = ((g[i + C] > g[i] + D) ? g[i + C] : g[i] + D);
}
h[x] = ret;
for(int i = 1;i <= _n;i ++)
h[x] = min(h[x],max(0,_d1 + i) + ret - g[i]);
}
else h[x] = ret + max(_d2,0);
}
int main() {
n = getint();
for(int i = 1;i <= n;i ++)
d[i] = getint();
for(int i = 1;i <= n;i ++)
c[i] = getint(),maxc = max(maxc,c[i]);
for(int i = 2;i <= n;i ++)
{
scanf("%d%d",&a,&b);
inser(a,b);
inser(b,a);
}
if(maxc <= 1) dfs(1,0); else bfs(1,0);
printf("%d",f[1]);
}