Codeforces 379F New Year Tree 树的直径的性质推理
我们假设当前的直径两端为A, B, 那么现在加入v的两个儿子x, y。
求直径的话我们可以第一次dfs找到最远点这个点必定为直径上的点, 然而用这个点第二次dfs找到最远点, 这两个点就是直径。
因为A, B现在是直径的两端, 那么从v点dfs找到的最远点必定为A或者B, 那么从 x dfs找到的最远点也必定为A或者B, 那么如果有
新的直径其中一个端点不会变, 当前图和原图的差别就是x和y, 那么比较dist(A, x), dist(B, x)和未加入前直径的长度就能得到当前的直径。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 1e6 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; int f[N][20], depth[N]; int q; int getLca(int u, int v) { if(depth[u] < depth[v]) swap(u, v); for(int i = 19; i >= 0; i--) if(depth[f[u][i]] >= depth[v]) u = f[u][i]; if(u == v) return u; for(int i = 19; i >= 0; i--) if(f[u][i] != f[v][i]) u = f[u][i], v = f[v][i]; return f[u][0]; } int dist(int u, int v) { int lca = getLca(u, v); return depth[u] + depth[v] - 2 * depth[lca]; } int main() { depth[1] = 1; depth[2] = depth[3] = depth[4] = 2; f[2][0] = f[3][0] = f[4][0] = 1; int A = 2, B = 3, dia = 2, n = 4; scanf("%d", &q); while(q--) { int v; scanf("%d", &v); depth[n + 1] = depth[v] + 1; depth[n + 2] = depth[v] + 1; f[n + 1][0] = f[n + 2][0] = v; for(int i = 1; i < 20; i++) { f[n + 1][i] = f[f[n + 1][i - 1]][i - 1]; f[n + 2][i] = f[f[n + 2][i - 1]][i - 1]; } int d1 = dist(A, n + 1); int d2 = dist(B, n + 1); if(d1 > dia) dia = d1, B = n + 1; else if(d2 > dia) dia = d2, A = n + 1; printf("%d\n", dia); n += 2; } return 0; } /* */