GMOJ 6807 tree 題解
阿新 • • 發佈:2020-11-01
把問題轉化
-
選取一個子樹包含所有顏色,答案為子樹外到子樹根最長鏈的長度
-
選取一個子樹使得原樹去掉該子樹包含所有顏色,答案為子樹內到子樹根最長鏈的長度
那麼以上情況取最大值即為答案。把問題轉化成了求子樹的顏色種類,是典型的DSU on Tree.
分開來做即可。
但仍需常數優化,預處理從下向上的最長鏈和次長鏈,兩種情況一起做。
#include <algorithm> #include <cstdio> using namespace std; const int maxn = 1000000, maxm = 100000; class Tree { public: int n, m, col[maxn + 1], ind[maxn + 1], to[2 * maxn - 1], link[2 * maxn - 1], son[maxn + 1], size[maxn + 1], len[maxn + 1], ans, f[maxm + 1], g[maxm + 1], ver[maxm + 1], ml[maxn + 1], sl[maxn + 1]; void addSide(int u, int v) { m++; to[m] = v; link[m] = ind[u]; ind[u] = m; } void init(int o, int fa) { len[o] = 1, size[o] = 1, son[o] = 0, ml[o] = 0, sl[o] = 0; for (int i = ind[o]; i; i = link[i]) { if (to[i] != fa) { init(to[i], o); len[o] = max(len[o], len[to[i]] + 1); if (len[ml[o]] <= len[to[i]]) { sl[o] = ml[o], ml[o] = to[i]; } else if (len[sl[o]] <= len[to[i]]) { sl[o] = to[i]; } size[o] += size[to[i]]; if (size[son[o]] < size[to[i]]) { son[o] = to[i]; } } } } void solve(int o, int fa, int up, bool keep, bool makeAns) { int a = ml[o], b = sl[o]; for (int i = ind[o]; makeAns && i; i = link[i]) { if (to[i] != fa && to[i] != son[o]) { solve(to[i], o, max(up, to[i] == a ? len[b] : len[a]) + 1, false, true); } } if (son[o]) { solve(son[o], o, max(up, son[o] == a ? len[b] : len[a]) + 1, true, makeAns); } for (int i = ind[o]; i; i = link[i]) { if (to[i] != fa && to[i] != son[o]) { solve(to[i], o, 0, true, false); } } if (ver[col[o]] != ver[0]) { ver[col[o]] = ver[0]; g[col[o]] = 0; } if (!g[col[o]]) { f[0]++; } g[col[o]]++; if (g[col[o]] == f[col[o]]) { g[0]++; } if (makeAns) { if (f[0] == col[0]) { ans = max(ans, up + 1); } if (!g[0]) { ans = max(ans, len[o] + 1); } } if (!keep) { ver[0]++, f[0] = g[0] = 0; } } }; int read() { int ret = 0; char c; for (c = getchar(); c < '0' || c > '9'; c = getchar()); for (; c >= '0' && c <= '9'; c = getchar()) { ret = ret * 10 + c - '0'; } return ret; } int main() { freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); static Tree tree; int n = read(), m = read(); tree.n = n; tree.col[0] = m; for (int i = 1; i <= n; i++) { tree.col[i] = read(); tree.f[tree.col[i]]++; } for (int i = 1; i < n; i++) { int u = read(), v = read(); tree.addSide(u, v); tree.addSide(v, u); } tree.g[0] = m; tree.init(1, 0); tree.solve(1, 0, 0, true, true); printf("%d\n", tree.ans); fclose(stdin); fclose(stdout); return 0; }