1. 程式人生 > >【LOJ2330】「清華集訓 2017」榕樹之心

【LOJ2330】「清華集訓 2017」榕樹之心

【題目連結】

【思路要點】

  • 首先,樹是二分圖,只有一側的點可能成為心。
  • 維護每一棵子樹會產生的向下推動的次數可能的最大值 M a x Max
    和最小值 M i n Min ,在奇偶性與 M a
    x Max
    M i n Min 相同時,任意一個 M
    i n Min
    M a x Max 中的數值都能夠被取到。
  • 樹形 d p dp 求得將每一個點 i i 1 1 號節點的一條鏈縮成一個點當做根的時候的 M a x Max M i n Min ,判斷 M i n Min 是否為 0 0 即可。
  • 時間複雜度 O ( T N ) O(T*N)

【程式碼】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
template <typename T> void read(T &x) {
	int f = 1; x = 0;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
struct info {
	bool odd;
	int Min, Max;
};
info operator + (info a, int b) {
	info ans = a;
	ans.Min += b;
	ans.Max += b;
	ans.odd = ans.Max & 1;
	return ans;
}
info operator + (info a, info b) {
	info ans;
	ans.Max = a.Max + b.Max;
	ans.odd = ans.Max & 1;
	if (a.Min > b.Min) swap(a, b);
	if (a.Max > b.Min) ans.Min = ans.odd;
	else ans.Min = b.Min - a.Max;
	return ans;
}
int type, T, n;
int size[MAXN];
info val[MAXN];
vector <info> pre[MAXN], suf[MAXN], mid[MAXN];
vector <int> a[MAXN];
char ans[MAXN];
void work(int pos, int fa) {
	val[pos] = (info) {0, 0, 0};
	size[pos] = 1;
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i] != fa) {
			work(a[pos][i], pos);
			size[pos] += size[a[pos][i]];
			val[pos] = val[pos] + (val[a[pos][i]] + 1);
		}
	if (a[pos].size() == 1) {
		mid[pos][0] = (info) {0, 0, 0};
		return;
	}
	if (a[pos][0] == fa) pre[pos][0] = (info) {0, 0, 0};
	else pre[pos][0] = (val[a[pos][0]] + 1);
	for (int i = 1; i < a[pos].size(); i++)
		if (a[pos][i] == fa) pre[pos][i] = pre[pos][i - 1];
		else pre[pos][i] = pre[pos][i - 1] + (val[a[pos][i]] + 1);
	if (a[pos][a[pos].size() - 1] == fa) suf[pos][a[pos].size() - 1] = (info) {0, 0, 0};
	else suf[pos][a[pos].size() - 1] = (val[a[pos][a[pos].size() - 1]] + 1);
	for (int i = a[pos].size() - 2; i >= 0; i--)
		if (a[pos][i] == fa) suf[pos][i] = suf[pos][i + 1];
		else suf[pos][i] = suf[pos][i + 1] + (val[a[pos][i]] + 1);
	mid[pos][0] = suf[pos][1];
	mid[pos][a[pos].size() - 1] = pre[pos][a[pos].size() - 2];
	for (unsigned i = 1; i < a[pos].size() - 1; i++)
		mid[pos][i] = pre[pos][i - 1] + suf[pos][i + 1];
}
void getans(int pos, int fa, info cnt) {
	info tmp = cnt + val[pos];
	if (tmp.Min == 0) ans[pos] = 49;
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i] != fa) getans(a[pos][i], pos, cnt + mid[pos][i]);
}
int main() {
	read(type), read(T);
	while (T--) {
		read(n);
		for (int i = 1; i <= n; i++) {
			a[i].clear();
			pre[i].clear();
			suf[i].clear();
			mid[i].clear();
		}
		for (int i = 1; i <= n - 1; i++) {
			int x, y;
			read(x), read(y);
			a[x].push_back(y);
			a[y].push_back(x);
		}
		if (n == 1) {
			printf("1\n");
			continue;
		}
		for (int i = 1; i <= n; i++) {
			ans[i] = 48;
			pre[i].resize(a[i].size());
			mid[i].resize(a[i].size());
			suf[i].resize(a[i].size());
		}
		ans[n + 1] = 0;
		work(1, 0);
		getans(1, 0, (info) {0, 0, 0});
		if (type == 3) printf("%c\n", ans[1]);
		else printf("%s\n", ans + 1);
	}
	return 0;
}