题意:每次操作新加两个叶子节点,每次操作完以后询问树的直径。
维护树的直径的两个端点U,V,每次计算一下新加进来的叶子节点到U,V两点的距离,如果有更长的就更新。
因为根据树的直径的求法,若出现新的直径,一定是到U或者到V距离最远。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 6 const int maxn = 1000000 + 1000; 7 const int logmaxn = 20; 8 9 int n, Q; 10 11 int L[maxn]; 12 int fa[maxn]; 13 int anc[maxn][logmaxn]; 14 15 void add(int u, int pa) 16 { 17 fa[u] = pa; 18 L[u] = L[pa] + 1; 19 anc[u][0] = pa; 20 for(int j = 1; (1 << j) < n; j++) if(anc[u][j-1]) 21 anc[u][j] = anc[anc[u][j-1]][j-1]; 22 } 23 24 int LCA(int p, int q) 25 { 26 if(L[p] < L[q]) std::swap(p, q); 27 int log; 28 for(log = 1; (1 << log) <= L[p]; log++); log--; 29 for(int i = log; i >= 0; i--) 30 if(L[p] - (1 << i) >= L[q]) p = anc[p][i]; 31 if(p == q) return p; 32 for(int i = log; i >= 0; i--) 33 if(anc[p][i] && anc[p][i] != anc[q][i]) 34 p = anc[p][i], q = anc[q][i]; 35 return fa[p]; 36 } 37 38 int distance(int u, int v) 39 { 40 int l = LCA(u, v); 41 return L[u] + L[v] - L[l] * 2; 42 } 43 44 int main() 45 { 46 scanf("%d", &Q); 47 n = 4; 48 fa[2] = fa[3] = fa[4] = 1; 49 L[2] = L[3] = L[4] = 1; 50 anc[2][0] = anc[3][0] = anc[4][0] = 1; 51 52 int U = 2, V = 3, diameter = 2; 53 while(Q--) 54 { 55 int p; scanf("%d", &p); 56 add(++n, p); 57 add(++n, p); 58 int l1 = distance(n, U), l2 = distance(n, V); 59 if(l1 >= l2 && l1 >= diameter) 60 { 61 V = n; 62 diameter = l1; 63 } 64 else if(l2 >= l1 && l2 >= diameter) 65 { 66 U = n; 67 diameter = l2; 68 } 69 printf("%d\n", diameter); 70 } 71 72 return 0; 73 }
代码君
时间: 2024-11-08 21:27:29