F. New Year Tree

F. New Year Tree

You are a programmer and you have a New Year Tree (not the traditional fur tree, though) — a tree of four vertices: one vertex of degree three (has number $1$), connected with three leaves (their numbers are from $2$ to $4$).

On the New Year, programmers usually have fun. You decided to have fun as well by adding vertices to the tree. One adding operation looks as follows:

First we choose some leaf of the tree with number $v$.
Let's mark the number of vertices on the tree at this moment by variable $n$, then two vertexes are added to the tree, their numbers are $n + 1$ and $n + 2$, also you get new edges, one between vertices $v$ and $n + 1$ and one between vertices $v$ and $n + 2$.
Your task is not just to model the process of adding vertices to the tree, but after each adding operation print the diameter of the current tree. Come on, let's solve the New Year problem!

Input

The first line contains integer $q$ $(1 \leq q \leq 5 \cdot 10^5)$ — the number of operations. Each of the next $q$ lines contains integer $v_i$ $(1 \leq v_i \leq n)$ — the operation of adding leaves to vertex $v_i$. Variable $n$ represents the number of vertices in the current tree.

It is guaranteed that all given operations are correct.

Output

Print $q$ integers — the diameter of the current tree after each operation.

Examples

input

5
2
3
4
8
5

output

3
4
4
5
6

 

解题思路

  不妨假设当前树中直径的两个端点为 $a$ 和 $b$,现在要往 $p$ 插入的两个儿子为 $x$ 和 $y$。显然我们只需考虑 $x$ 和 $y$ 是否为新的直径端点,由于 $x$ 和 $y$ 是等价的,这里我们只考虑 $x$。

  如果 $x$ 不是新的直径端点,那么此时树中直径的端点仍是 $a$ 和 $b$。

  否则 $x$ 是新的直径端点,由树的直径的性质知道,直径的另外一个端点就是距离 $x$ 最远的节点。由于 $x$ 和 $y$ 是 $p$ 的儿子,等价于求距离 $p$ 最远的节点。同样由性质知道,距离 $p$ 最远的节点必定是任意直径中的其中一个端点。由于 $x$ 和 $y$ 不是距离 $p$ 最远的节点,现在我们只需考虑在插入 $x$ 和 $y$ 前的树中,距离 $p$ 最远的节点,也就是 $a$ 或 $b$。$\text{dist}(a,p)$ 和 $\text{dist}(b,p)$ 中的较大者就是距离 $x$ 最远的节点。

  所以在插入 $x$ 和 $y$ 后,判断 $x$ 能否作为新的直径节点的依据是 $\text{dist}(a,x) > \text{dist}(a,b)$ 或 $\text{dist}(b,x) > \text{dist}(a,b)$ 是否成立。例如,$\text{dist}(a,x) > \text{dist}(a,b)$ 成立的话,则令 $b \gets x$。否则 $\text{dist}(b,x) > \text{dist}(a,b)$ 成立则令 $a \gets x$。否则直径端点仍是 $a$ 和 $b$。

  为了求 $\text{dist}(a,b)$,我们需要用到 lca,因此在插入 $x$ 和 $y$ 的过程中动态维护倍增数组。

  AC 代码如下,时间复杂度为 $O(q\log{q})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 1e6 + 10;

int sz = 1;
int fa[N][20], dep[N];

void add(int u) {
    int v = ++sz;
    dep[v] = dep[u] + 1;
    fa[v][0] = u;
    for (int i = 1; i <= 19; i++) {
        fa[v][i] = fa[fa[v][i - 1]][i - 1];
    }
}

int lca(int a, int b) {
    if (dep[a] < dep[b]) swap(a, b);
    for (int i = 19; i >= 0; i--) {
        if (dep[fa[a][i]] >= dep[b]) a = fa[a][i];
    }
    if (a == b) return a;
    for (int i = 19; i >= 0; i--) {
        if (fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i];
    }
    return fa[a][0];
}

int dist(int a, int b) {
    return dep[a] + dep[b] - 2 * dep[lca(a, b)];
}

int main() {
    int n;
    scanf("%d", &n);
    dep[1] = 1;
    for (int i = 0; i < 3; i++) {
        add(1);
    }
    int a = 2, b = 3;
    while (n--) {
        int x;
        scanf("%d", &x);
        add(x), add(x);
        if (dist(a, sz - 1) > dist(a, b)) b = sz - 1;
        else if (dist(b, sz - 1) > dist(a, b)) a = sz - 1;
        printf("%d\n", dist(a, b));
    }
    
    return 0;
}

 

参考资料

  Codeforces379 F. New Year Tree - DennyQi - 博客园:https://www.cnblogs.com/qixingzhi/p/9309102.html

posted @ 2024-04-08 16:32  onlyblues  阅读(2)  评论(0编辑  收藏  举报
Web Analytics