【题目链接】
【思路要点】
- 首先,树是二分图,只有一侧的点可能成为心。
- 维护每一棵子树会产生的向下推动的次数可能的最大值 M a x Max Max 和最小值 M i n Min Min ,在奇偶性与 M a x Max Max 和 M i n Min Min 相同时,任意一个 M i n Min Min 至 M a x Max Max 中的数值都能够被取到。
- 树形 d p dp dp 求得将每一个点 i i i 至 1 1 1 号节点的一条链缩成一个点当做根的时候的 M a x Max Max 和 M i n Min Min ,判断 M i n Min Min 是否为 0 0 0 即可。
- 时间复杂度 O ( T ∗ N ) 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; }