- 最大值很好求,注意树形dp考虑一棵子树时根节点一定选,不管是不是负的。
- 方案的差别是选择城镇的差别所以有两种情况:1.一棵子树中选择k个节点时从大到小第k+1个节点和k节点值相同。2.存在最值为0的节点
- 但是出现以上情况的节点不一定能向上转移,也就是出现在最优方案中,我们只要再开一个dp数组f,表示当前子树有无多种方案。跟着求最值数组一起转移就行了。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define PII pair<ll, ll>
const int N = 1e5 + 5;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double PI = acos(-1.0);
int h[N], e[N << 1], ne[N << 1], idx;
int val[N], tim[N]; ll dp[N]; bool f[N];
int n;
void add ( int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs( int u, int fa ) {
dp[u] = val[u];
vector<pair<ll, int> > tmp;
for ( int i = h[u]; ~i; i = ne[i]) {
int v = e[i]; if( v == fa ) continue;
dfs(v, u);
}
for ( int i = h[u]; ~i; i = ne[i]) {
int v = e[i]; if( v == fa ) continue;
tmp.push_back({dp[v], v});
}
sort(tmp.begin(), tmp.end(), [](PII A, PII B){ return A.first > B.first; });
int cnt = 0;
bool ok = 0; if(dp[u] > 0) ok = 1;
for ( int i = 0; i < min((int)tmp.size(), tim[u]); ++ i ) {
if(tmp[i].first < 0) break;
++ cnt; if(!tmp[i].first) f[tmp[i].second] = 1; //选的方案中存在0,可选不选
dp[u] += dp[tmp[i].second]; f[u] |= f[tmp[i].second];
}
if((tmp.size() > cnt && tmp[cnt] == tmp[cnt - 1])) f[u] = 1; //选cnt个,并且cnt和cnt+1相同 当且有多种方案
}
int main () {
IOS
memset(h, -1, sizeof h);
cin >> n;
for ( int i = 2; i <= n ; ++ i ) cin >> val[i];
for ( int i = 2; i <= n; ++ i ) cin >> tim[i], tim[i] -= 1; tim[1] = n;
for ( int i = 1; i <= n - 1; ++ i ) {
int u, v; cin >> u >> v;
add(u, v), add(v, u);
}
dfs (1, -1);
cout << dp[1] << endl;
if(f[1]) cout << "solution is not unique" << endl; else cout << "solution is unique" << endl;
return 0;
}