Good Bye 2013 F. New Year Tree 倍增、思维
题目链接
题目大意
初始有一颗4个顶点的数, 1 1 1号点的度数为 3 3 3, 2 2 2 到 4 4 4 号点为叶子结点。 q q q ( 1 ≤ q ≤ 5 ∗ 1 0 5 ) (1 \leq q \leq 5*10^5) (1≤q≤5∗105)次操作,每次操作如下:
- 首先,选择树中编号为 v v v的叶子结点。
- 用
n
n
n表示此刻树上的结点数,然后向树上添加两个顶点,编号分别为
n
+
1
n+1
n+1、
n
+
2
n+2
n+2,同时得到新的边,一条在
v
v
v与
n
+
1
n+1
n+1之间,另一条在
v
v
v与
n
+
2
n+2
n+2之间。
每次询问输出当前树的直径。
思路
首先,树的直径一定是叶子结点到叶子结点。
设当前直径为 d 1 d_1 d1到 d 2 d_2 d2,若添加一个叶子结点 v v v,直径的变化有三种情况: ( 1 ) 、 (1)、 (1)、保持不变仍为 d 1 d_1 d1 到 d 2 d_2 d2 ; ( 2 ) 、 (2)、 (2)、变为 v v v 到 d 1 d_1 d1 ; ( 3 ) 、 (3)、 (3)、变为 v v v 到 d 2 d_2 d2 。只需要每次加入点都看看这三种情况,取一个最大的即可。
计算直径的大小可以借助 l c a lca lca来计算, u u u到 v v v的距离 d = d= d= d e e p t h ( u ) + d e e p t h ( v ) − 2 ∗ d e e p t h ( l c a ( u , v ) ) deepth(u)+deepth(v)-2*deepth(lca(u,v)) deepth(u)+deepth(v)−2∗deepth(lca(u,v)).
code
#include <bits/stdc++.h>
#define ll long long
#define pii pair<int, int>
using namespace std;
const int N = 5e5 + 10, M = N * 2;
int deepth[M], anc[M][21];
vector<int> a[M];
int d[2] = {2, 3}, t[2];
void dfs(int x, int fa)
{
deepth[x] = deepth[fa] + 1;
anc[x][0] = fa;
for (int i = 1; i < 21; ++i)
anc[x][i] = anc[anc[x][i - 1]][i - 1];
for (auto k : a[x])
{
if (k == fa)
continue;
dfs(k, x);
}
}
int lca(int a, int b)
{
if (deepth[a] < deepth[b])
swap(a, b);
for (int i = 20; i >= 0; --i)
if (deepth[anc[a][i]] >= deepth[b])
a = anc[a][i];
if (a == b)
return b;
for (int i = 20; i >= 0; --i)
{
if (anc[a][i] != anc[b][i])
{
a = anc[a][i];
b = anc[b][i];
}
}
return anc[a][0];
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int idx = 2;
for (int i = 0; i < 3; ++i)
{
a[1].push_back(idx);
a[idx++].push_back(1);
}
dfs(1, 0);
int len = 2;
int q;
cin >> q;
for (int i = 0; i < q; ++i)
{
int x;
cin >> x;
t[0] = idx, t[1] = idx + 1;
a[x].push_back(idx);
a[idx].push_back(x);
dfs(idx, x);
idx++;
a[x].push_back(idx);
a[idx].push_back(x);
dfs(idx, x);
idx++;
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k)
{
int tmp1 = lca(t[j], d[k]);
int tmp2 = deepth[t[j]] + deepth[d[k]] - deepth[tmp1] * 2;
if (tmp2 > len)
{
len = tmp2;
d[1 - k] = t[j];
}
}
cout << len << '\n';
}
return 0;
}