1. 程式人生 > >[Usaco2018 Feb] New Barns

[Usaco2018 Feb] New Barns

[題目連結]

        https://www.lydsy.com/JudgeOnline/problem.php?id=5192

[演算法]

        維護樹的直徑,在樹上離一個點最遠的點一定是一條直徑的端點。

        在直徑為(x , y)的樹上加入一個葉子結點z,則新的直徑必然為(x , y) , (x , z) , (y , z)中的一條 , 問題轉化為詢問樹上兩點距離 , 倍增即可 , 時間複雜度 :O(MlogN)

[程式碼]

         

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
const int MAXLOG = 20;

int n , total , k;
int depth[MAXN] , x[MAXN] , y[MAXN] , belong[MAXN];
int anc[MAXN][MAXLOG];
char op[5];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template 
<typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1
) + c - '0'; x *= f; } inline int lca(int u,int v) { if (depth[u] > depth[v]) swap(u , v); for (int i = MAXLOG - 1; i >= 0; i--) { if (depth[anc[v][i]] >= depth[u]) v = anc[v][i]; } if (u == v) return u; for (int i = MAXLOG - 1; i >= 0; i--) { if (anc[u][i] != anc[v][i]) u = anc[u][i] , v = anc[v][i]; } return anc[u][0]; } inline int dist(int x,int y) { return depth[x] + depth[y] - 2 * depth[lca(x , y)]; } inline void update(int u) { int tmp = belong[u]; int nx , ny , nd; if (dist(u , x[tmp]) > dist(u , y[tmp])) { nd = dist(u , x[tmp]); nx = u; ny = x[tmp]; } else { nd = dist(u , y[tmp]); nx = u; ny = y[tmp]; } if (nd > dist(x[tmp] , y[tmp])) { x[tmp] = nx; y[tmp] = ny; } } inline int query(int k) { int tmp = belong[k]; return max(dist(k , x[tmp]) , dist(k , y[tmp])); } int main() { int Q; scanf("%d",&Q); while (Q--) { scanf("%s%d",&op , &k); if (op[0] == 'B') { ++n; if (k == -1) { belong[n] = ++total; anc[n][0] = 0; depth[n] = 1; x[total] = y[total] = n; } else { depth[n] = depth[k] + 1; anc[n][0] = k; for (int i = 1; i < MAXLOG; i++) anc[n][i] = anc[anc[n][i - 1]][i - 1]; belong[n] = belong[k]; } update(n); } else printf("%d\n",query(k)); } return 0; }