【LOJ2330】「清華集訓 2017」榕樹之心
阿新 • • 發佈:2018-11-08
【題目連結】
【思路要點】
- 首先,樹是二分圖,只有一側的點可能成為心。
- 維護每一棵子樹會產生的向下推動的次數可能的最大值
和最小值 ,在奇偶性與 和 相同時,任意一個 至 中的數值都能夠被取到。- 樹形 求得將每一個點 至 號節點的一條鏈縮成一個點當做根的時候的 和 ,判斷 是否為 即可。
- 時間複雜度 。
【程式碼】
#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; }