constint N = 1000010, M = 2000010; typedeflonglong LL; int n, h[N], sz[N], idx = 2; structEdge { int to, nxt; } e[M]; LL mx, sum[N]; int mxp;
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
voiddfs(int u, int fa){ sz[u] = 1; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == fa) continue; dfs(to, u); sz[u] += sz[to]; sum[u] += sum[to] + sz[to]; } }
voiddp(int u, int fa){ if (fa) sum[u] += sum[fa] - sum[u] - sz[u] + n - sz[u]; if (sum[u] > mx) mx = sum[u], mxp = u; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == fa) continue; dp(to, u); } }
intmain(){ scanf("%d", &n); for (int i = 1, a, b; i < n; i++) { scanf("%d%d", &a, &b); add(a, b), add(b, a); } dfs(1, 0); dp(1, 0); return !printf("%d\n", mxp); }
typedeflonglong LL; constint N = 200010, M = 400010, P = 1e9+7; int h[N], e[M], ne[M], res[N], n, idx; LL dp[N], sz[N];
voidadd(int a, int b){ e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
LL qmi(LL a, LL k){ LL res = 1; while (k) { if (k & 1) res = res * a % P; a = a * a % P; k >>= 1; } return res; }
voiddfs(int u, int fa){ sz[u] = 1; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (j == fa) continue; dfs(j, u); sz[u] += sz[j]; } dp[u] = sz[u]; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (j == fa) continue; dp[u] = dp[u] * dp[j] % P; } }
voiddfs_dp(int u, int fa){ if (fa) dp[u] = dp[fa] * (n-sz[u]) % P * qmi(sz[u], P-2) % P; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (j == fa) continue; dfs_dp(j, u); } }
intmain(){ memset(h, -1, sizeof h); scanf("%d", &n); for (int i = 1, a, b; i < n; i++) { scanf("%d%d", &a, &b); add(a, b), add(b, a); } dfs(1, 0); dfs_dp(1, 0); LL fracn = 1; for (int i = 2; i <= n; i++) fracn = fracn * i % P; for (int i = 1; i <= n; i++) printf("%lld\n", fracn * qmi(dp[i], P-2) % P); return0; }
constint N = 300010, M = 600010, K = 19; int n; int h[N], sz[N], p[N], f[N][K]; longlong res = 0;
int idx = 2; structEdge { int to, nxt; } e[M];
voidadd(int a, int b){ e[idx] = {b, h[a]}, h[a] = idx++; }
voidcalc_res(int u){ int n = sz[u]; for (int k = K-1; k >= 0; k--) if (f[u][k] && n - sz[f[u][k]] <= n / 2) u = f[u][k];
res += u; if (n % 2 == 0 && sz[u] == n/2) res += p[u]; }
voidcalc_f(int u, int s){ f[u][0] = s; for (int k = 1; k < K; k++) f[u][k] = f[f[u][k-1]][k-1]; }
voiddfs(int u, int fa){ sz[u] = 1, p[u] = fa; int s = 0; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == fa) continue; dfs(to, u); sz[u] += sz[to]; if (sz[s] < sz[to]) s = to; } calc_f(u, s); }
voiddp(int u, int fa){ int su = f[u][0], szu = sz[u];
// dp 的过程中找重儿子和次重儿子比较好 int s1 = 0, s2 = 0; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (sz[to] > sz[s1]) s2 = s1, s1 = to; elseif (sz[to] > sz[s2]) s2 = to; } for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == fa) continue; calc_res(to);
if (to == s1) calc_f(u, s2); elsecalc_f(u, s1);
p[u] = to; sz[u] = n - sz[to];
calc_res(u);
dp(to, u); }
p[u] = fa, sz[u] = szu; calc_f(u, su); }
voidsolve(){ scanf("%d", &n); idx = 2; for (int i = 1; i <= n; i++) h[i] = 0;
for (int i = 1, a, b; i < n; i++) { scanf("%d%d", &a, &b); add(a, b), add(b, a); }
res = 0; dfs(1, 0); dp(1, 0);
printf("%lld\n", res); }
intmain(){ int T; scanf("%d", &T);
while (T--) solve();
return0; }
事实上,你也可以判断重儿子是否 >n/2,这样会倍增到最后一个不满足重心要求的点。
但是这样需要特判根为重心的情况,有些麻烦,下面是一个被验证过的正确的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
pair<int, int> calc_res2(int u){ int n = sz[u], v = 0; if (sz[f[u][0]] <= n / 2) { if (n % 2 == 0 && sz[f[u][0]] == n / 2) v = f[u][0]; return {u, v}; }
for (int k = K-1; k >= 0; k--) if (f[f[u][k]][0] && sz[f[f[u][k]][0]] > n / 2) u = f[u][k]; u = f[u][0]; if (n % 2 == 0 && sz[f[u][0]] == n/2) v = f[u][0]; return {u, v}; }
[CF685B] Kay and Snowflake
给定 n 个点的树和 q 次询问,每次询问一个点 u,求以 u 为根时重心的标号,若有多个输出任意一个。