题解:P4572 [JSOI2013] 哈利波特与死亡圣器
posted on 2024-12-12 10:42:21 | under | source
具有单调性,二分答案 \(k\),考虑判定。
可以发现,伏地魔是不会走回头路的。设当前点 \(u\) 的父亲是 \(fa\),则当伏地魔先前在 \(fa\) 处时肯定是不存在一个未被保护的相邻节点,不然走过去就赢了。那从 \(u\to fa\) 再走到另一个节点肯定不如在 \(fa\) 时直接向那个点走去,因为被保护的点肯定更多了。同时,假如伏地魔走到了 \(u\),那么接下来我们只会对 \(u\) 子树内的点进行保护。
无后效性可以树形 dp。考虑 \(f_u\) 表示伏地魔在 \(u\) 点出发向子树内走去,若要成功防御则至少还需要提前保护多少个点。转移是容易的,\(f_u\gets \max(0,(\sum\limits_{v\in son} 1+f_v)-k)\),因为我们在伏地魔行动前操作,而无法得知他具体往哪走,所以必须让每个儿子子树都合法。
复杂度 \(O(n\log n)\)。
闲话:是因为题目名字有趣所以开的这道题,感觉比较水,顶多评个蓝吧。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
int n, u, v, k, f[N];
vector<int> to[N];
inline void dfs(int u, int fa){
f[u] = 0;
for(auto v : to[u])
if(v ^ fa) dfs(v, u), f[u] += 1 + f[v];
f[u] = max(0, f[u] - k);
}
signed main(){
cin >> n;
for(int i = 1; i < n; ++i) scanf("%d%d", &u, &v), to[u].push_back(v), to[v].push_back(u);
int L = -1, R = n, mid;
while(L + 1 < R){
mid = (L + R) >> 1;
k = mid, dfs(1, 0);
if(!f[1]) R = mid;
else L = mid;
}
cout << R;
return 0;
}

浙公网安备 33010602011771号