[bzoj3420]Poi2013 Triumphal arch_树形dp_二分

Triumphal arch

题目链接https://lydsy.com/JudgeOnline/problem.php?id=3420

数据范围:略。


题解

首先,发现$ k $具有单调性,我们可以二分。

现在考虑怎么验证?

看了题解...

我们设$ f_i $表示,如果当前人在$i$且要求合法的情况下,$i$的子树中最多要预先处理好多少个节点。

然后暴力树形$dp$转移即可。

代码

#include <bits/stdc++.h>

#define N 1000010 

using namespace std;

char *p1, *p2, buf[100000];

#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )

int rd() {
	int x = 0, f = 1;
	char c = nc();
	while (c < 48) {
		if (c == '-')
			f = -1;
		c = nc();
	}
	while (c > 47) {
		x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
	}
	return x * f;
}

int head[N], to[N << 1], nxt[N << 1], tot;

inline void add(int x, int y) {
	to[ ++ tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
}

int sz[N], ssz[N];

void dfs1(int p, int fa) {
	sz[p] = 1;
	for (int i = head[p]; i; i = nxt[i]) {
		if (to[i] != fa) {
			ssz[p] ++ ;
			dfs1(to[i], p);
			sz[p] += sz[to[i]];
		}
	}
}
int k, f[N];

void dfs(int p, int fa) {
	f[p] = -k;
	for (int i = head[p]; i; i = nxt[i]) {
		if (to[i] != fa) {
			dfs(to[i], p);
			f[p] += f[to[i]] + 1;
		}
	}
	f[p] = max(f[p], 0);
}

bool check(int x) {
	k = x;
	dfs(1, 1);
	if (f[1]) {
		return false;
	}
	else {
		return true;
	}
}

int main() {
	int n = rd();
	for (int i = 1; i < n; i ++ ) {
		int x = rd(), y = rd();
		add(x, y), add(y, x);
	}
	dfs1(1, 1);
	if (n == 1) {
		puts("0");
		return 0;
	}
	int l = 1, r = n, ans = n;
	while (l <= r) {
		int mid = (l + r) >> 1;
		// cout << mid << endl ;
		if (check(mid)) {
			r = mid - 1;
			ans = mid;
		}
		else {
			l = mid + 1;
		}
	}
	cout << ans << endl ;
	return 0;
}

 

posted @ 2019-10-31 20:21  JZYshuraK_彧  阅读(212)  评论(0编辑  收藏  举报