思路:树上启发式合并
先跑轻子树,然后清除轻子树的信息
最后跑重子树,不清除信息
然后再跑一遍轻子树,重新加回轻子树的信息
由于一个节点到根节点最多有logn个轻边,所以复杂度为nlogn
代码:
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pi acos(-1.0) #define LL long long //#define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pii pair<int, int> #define piii pair<pii, int> #define mem(a, b) memset(a, b, sizeof(a)) #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout); //head const int N = 1e6 + 5; vector<int>g[N]; map<int, int>mp; int deep[N], sz[N], bs[N], ans[N], mx = 0; void dfs(int o, int u) { deep[u] = deep[o] + 1; sz[u] = 1; for (int v : g[u]) { if(v != o) { dfs(u, v); sz[u] += sz[v]; if(sz[v] > sz[bs[u]]) bs[u] = v; } } } void ADD(int o,int u) { mp[deep[u]]++; if(mp[deep[u]] > mp[mx] || mp[deep[u]] == mp[mx] && deep[u] < mx) mx = deep[u]; for (int v : g[u]) { if(v != o) { ADD(u, v); } } } void DFS(int o, int u) { for (int v : g[u]) { if(v != o && v != bs[u]) { DFS(u, v); mp.clear(); mx = 0; } } if(bs[u])DFS(u, bs[u]); for (int v : g[u]) { if(v != o && v != bs[u]) { ADD(u, v); } } mp[deep[u]]++; if(mp[deep[u]] > mp[mx] || mp[deep[u]] == mp[mx] && deep[u] < mx) mx = deep[u]; ans[u] = mx - deep[u]; } int main() { int n, u, v; scanf("%d", &n); for (int i = 1; i < n; i++) { scanf("%d %d", &u, &v); g[u].pb(v); g[v].pb(u); } dfs(0, 1); DFS(0, 1); for (int i = 1; i <= n; i++) printf("%d%c", ans[i], ' '); return 0; }