POI #Year2011 #二分 #树上dp
二分答案
对于每个点 \(dp_{x,0/1}\) 表示到 \(x\) ,\(dp_{x,0}\)表示最远的没有被覆盖的点的距离 ,\(dp_{x,1}\) 表示最近的被选中的点的距离
转移按照题意,如果可以覆盖就覆盖,否则当留下来不合法就加点
// Author: xiaruize
const int N = 3e5 + 10;
int head[N], to[N<<1], nxt[N<<1], tot;
void add(int u, int v)
{
tot++;
to[tot] = v;
nxt[tot] = head[u];
head[u] = tot;
}
int n, m;
bool st[N];
vector<int> g[N];
int cnt = 0;
pii dfs(int x, int fa, int lim)
{
pii cur = {-INF, INF};
for (int i = head[x]; i; i = nxt[i])
{
int v = to[i];
if (v == fa)
continue;
auto tmp = dfs(v, x, lim);
cur.first = max(cur.first, tmp.first + 1);
cur.second = min(cur.second, tmp.second + 1);
}
if (cur.first + cur.second <= lim)
cur.first = -INF;
if (cur.second > lim && st[x])
cur.first = max(cur.first, 0);
if (cur.first == lim)
{
cur = {-INF, 0};
cnt++;
}
return cur;
}
bool check(int x)
{
cnt = 0;
pii tmp = dfs(1, 0, x);
if (tmp.first >= 0)
cnt++;
return cnt <= m;
}
void solve()
{
cin >> n >> m;
rep(i, 1, n) cin >> st[i];
rep(i, 1, n - 1)
{
int u, v;
cin >> u >> v;
add(u, v);
add(v, u);
}
int l = 0, r = n;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid))
r = mid;
else
l = mid + 1;
}
cout << r << endl;
}
#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
#ifndef ONLINE_JUDGE
cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
return 0;
}
标签:tmp,cnt,cur,int,POI2011DYN,second,Dynamite,first
From: https://www.cnblogs.com/xiaruize/p/18147869