POI2011DYN-Dynamite

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;
}
posted @ 2024-04-20 16:47  xiaruize  阅读(6)  评论(0)    收藏  举报