Description
给出一棵树,除了叶子节点外要给其他节点打上 k 个 min 和 n - l - k 个 max 的 tag ,要求根节点的 max状态下最大可能值, min状态下最小可能值。
Solution
在所有节点必须放满的情况下,要么是叶子,要么是max/min
在贪心的条件下,如果只考虑要求最大值
最优的策略是把 max 放在深度较低的地方,即先取 min 再取 max 结果更优
于是考虑dfs,如果当前深度小于 n - l - k,就放 max, 否则放 min
最小值也可以相应处理。
注意观察样例,如果某一个节点只有一个儿子,则我们直接传到儿子,不需要考虑深度增加的问题,具体看一下代码。
Code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5 + 5; typedef long long ll; int a[N], son[N], l, n, k; vector<int> G[N]; ll dfs(int u, int par, int dep, bool solve_type) { //cout << "path:" << u << ' ' << par << endl; if(a[u]) { return a[u]; } else if(son[u] == 1) { for(auto &v : G[u]) { if(v == par) continue; return dfs(v, u, dep, solve_type); } } else if(solve_type) { // 求最大值 if(dep >= n - l - k) { ll ans = 1e18; for(auto &v : G[u]) { if(v == par) continue; ans = min(ans, dfs(v, u, dep + 1, solve_type)); } return ans; } else { ll ans = 0; for(auto &v : G[u]) { if(v == par) continue; ans = max(ans, dfs(v, u, dep + 1, solve_type)); } return ans; } } else { // 求最小值 if(dep >= k) { ll ans = 0; for(auto &v : G[u]) { if(v == par) continue; ans = max(ans, dfs(v, u, dep + 1, solve_type)); } return ans; } else { ll ans = 1e18; for(auto &v : G[u]) { if(v == par) continue; ans = min(ans, dfs(v, u, dep + 1, solve_type)); } return ans; } } } int main() { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); cin >> n >> k; for(int i = 2; i <= n; i++) { int u; cin >> u; G[i].push_back(u); G[u].push_back(i); son[u]++; } for(int i = 1; i <= n; i++) cin >> a[i], l += (a[i] > 0); cout << dfs(1, 0, 0, false) << ' ' << dfs(1, 0, 0, true) << "\n"; return 0; }