【题目链接】
【思路要点】
- 答案的第一位一定是编号最小的度数不为 3 3 3 的节点,不妨设为 r o o t root root ,以 r o o t root root 为根, i i i 的子树内编号最小的度数不为 3 3 3 的节点为 d p i dp_i dpi 。
- 在这个思路上,我们考虑如何比较 x x x 和 y y y 两点作为根节点时的答案哪个更优。
1 1 1 、当 l c a ( x , y ) ≠ x , y lca(x,y)\ne x,y lca(x,y)̸=x,y ,比较 l c a ( x , y ) lca(x,y) lca(x,y) 的 x x x 所在子树 l x lx lx 的 d p l x dp_{lx} dplx 和 y y y 所在子树 l y ly ly 的 d p l y dp_{ly} dply 。
2 2 2 、当 l c a ( x , y ) = x lca(x,y)= x lca(x,y)=x ( = y =y =y 同理), 比较 l c a ( x , y ) lca(x,y) lca(x,y) 的 y y y 所在子树 l y ly ly 的 d p l y dp_{ly} dply 和 l y ly ly 。(实际上不考虑这一点就可以通过原题的数据,但过不了样例……)- 如此,我们找到了最终答案的根节点, O ( N ) O(N) O(N) 找到最优答案即可。
- 时间复杂度 O ( N ) O(N) O(N) 。
【代码】
#include<bits/stdc++.h> const int MAXN = 1e6 + 5; const int INF = 1e9; using namespace std; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } const int MAXBUF = 1 << 23; char B[MAXBUF], *S = B, *T = B; char getc() { if (S == T) T = (S = B) + fread(B, 1, MAXBUF, stdin); if (S == T) return 0; else return *S++; } template <class T> void read(T &a) { static char c; static int fh; while (((c = getc()) < '0' || c > '9') && c != '-'); if (c == '-') fh = -1, a = 0; else fh = 1, a = c - '0'; while ((c = getc()) <= '9' && c >= '0') a = (a << 3) + (a << 1) + c - '0'; a *= fh; } char Buff[MAXBUF], *st = Buff; template <class T> void write(T a) { if (a == 0) *st++ = '0'; else { if (a < 0) *st++ = '-', a = -a; static char c[20]; static int c0; c0 = 0; while (a) c[c0++] = a % 10 + '0', a /= 10; while (c0--) *st++ = c[c0]; } } int n, k[MAXN], a[MAXN][4], ans[MAXN]; int minnum[MAXN], num[MAXN], tans[MAXN]; int tot, ansroot, vis[MAXN], dp[MAXN], father[MAXN]; void dfs(int pos, int fa) { int tmp = 0; if (fa) tmp = 1; if (k[pos] == tmp) { minnum[pos] = pos; return; } if (k[pos] - tmp == 1) { minnum[pos] = pos; for (int i = 1; i <= k[pos]; i++) if (a[pos][i] != fa) { dfs(a[pos][i], pos); minnum[pos] = min(minnum[pos], minnum[a[pos][i]]); } } else { minnum[pos] = INF; for (int i = 1; i <= k[pos]; i++) if (a[pos][i] != fa) { dfs(a[pos][i], pos); minnum[pos] = min(minnum[pos], minnum[a[pos][i]]); } } } void work(int pos, int fa) { int tmp = 0; if (fa) tmp = 1; if (k[pos] == tmp) { ans[++tot] = pos; return; } if (k[pos] - tmp == 1) { if (minnum[pos] == pos) ans[++tot] = pos; for (int i = 1; i <= k[pos]; i++) if (a[pos][i] != fa) work(a[pos][i], pos); if (minnum[pos] != pos) ans[++tot] = pos; } else { for (int i = 1; i <= k[pos]; i++) if (a[pos][i] != fa && minnum[pos] == minnum[a[pos][i]]) work(a[pos][i], pos); ans[++tot] = pos; for (int i = 1; i <= k[pos]; i++) if (a[pos][i] != fa && minnum[pos] != minnum[a[pos][i]]) work(a[pos][i], pos); } } void getans(int pos) { tot = 0; dfs(pos, 0); work(pos, 0); } void getdp(int pos, int fa) { father[pos] = fa; if (fa == 0) dp[pos] = pos; else dp[pos] = INF; if (k[pos] <= 2) chkmin(dp[pos], pos); for (int i = 1; i <= k[pos]; i++) if (a[pos][i] != fa) { getdp(a[pos][i], pos); chkmin(dp[pos], dp[a[pos][i]]); } } bool tryroot(int pos, int lca) { if (ansroot == 0) { ansroot = pos; return true; } if (lca != ansroot) { int newr = 0, oldr = 0; for (int i = 1; i <= k[lca]; i++) { if (a[lca][i] != father[lca] && vis[a[lca][i]] == 1) oldr = a[lca][i]; if (a[lca][i] != father[lca] && vis[a[lca][i]] == 2) newr = a[lca][i]; } bool ans = dp[newr] < dp[oldr]; if (ans) ansroot = pos; return ans; } else { int tmp = 0; for (int i = 1; i <= k[lca]; i++) if (a[lca][i] != father[lca] && vis[a[lca][i]] == 1) tmp = a[lca][i]; bool ans = tmp < dp[tmp]; if (ans) ansroot = pos; return ans; } } bool getroot(int pos, int fa, int lca) { bool ans = false; vis[pos] = 1; if (fa && k[pos] <= 2) ans |= tryroot(pos, lca); for (int i = 1; i <= k[pos]; i++) if (a[pos][i] != fa) { if (ans) getroot(a[pos][i], pos, pos); else ans |= getroot(a[pos][i], pos, lca); } vis[pos] = 2; return ans; } void update() { for (int i = 1; i <= n; i++) { if (tans[i] < ans[i]) break; if (tans[i] > ans[i]) return; } for (int i = 1; i <= n; i++) ans[i] = tans[i]; } int main() { read(n); for (int i = 1; i <= n; i++) { read(k[i]); for (int j = 1; j <= k[i]; j++) read(a[i][j]); } int root = INF; for (int i = 1; i <= n; i++) if (k[i] <= 2) { root = i; break; } getans(root); memcpy(tans, ans, sizeof(ans)); getdp(root, 0); getroot(root, 0, root); getans(ansroot); update(); for (int i = 1; i <= n; i++) write(ans[i]), *st++ = i == n? '\n' : ' '; fwrite(Buff, 1, st - Buff, stdout); return 0; }