Codeforces 379 F. New Year Tree


\(>Codeforces \space 379 F. New Year Tree<\)

题目大意 : 有一棵有 \(4\) 个节点个树,有连边 \((1,2) (1,3) (1,4)\) ,一共有 \(q\) 次操作,每次选择一个节点,新建两个节点 \(n + 1, n + 2\) 向其连边,每次操作完之后求树的直径的长度

$1 \leq q \leq 5 \times 10^5 $

解题思路 :

观察发现,每次加点后,树的直径的端点至多只会变化一个

证明:首先显然新的直径的端点不可能是两个新加的点,也不可能是两个原本不是直径端点的点

所以如果要使得新的直径的端点变化两个的话,那么必然有一个端点是新加的点

假设有新加的点 \(u\) ,其父亲是 \(fa\) ,离 \(fa\) 最远的点一定是树的直径的一个端点,那么此时离 \(u\) 最远的点也一定是树的直径一个端点. 至此产生矛盾,所以每次加点后,树的直径的端点至多只会变化一个

所以只需要每次加点动态维护倍增数组,用 \(lca\) 暴力判是否能更新掉一个直径端点即可,复杂度是 \(O(nlogn)\)



/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
#define N (1000005)
int f[N][23], dep[N], tot; 
inline void addson(int u){
    int v = ++tot; 
    dep[v] = dep[u] + 1, f[v][0] = u;
    for(int j = 1; j <= 22; j++) f[v][j] = f[f[v][j-1]][j-1];
}
inline int Lca(int x, int y){
    if(dep[x] < dep[y]) swap(x, y);
    for(int i = 22; i >= 0; i--){
        if(dep[f[x][i]] >= dep[y]) x = f[x][i];
        if(dep[x] == dep[y]) break;
    }
    if(x == y) return x;
    for(int i = 22; i >= 0; i--)
        if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    return f[x][0];
}
inline int dis(int x, int y){
    int lca = Lca(x, y); return dep[x] + dep[y] - 2 * dep[lca]; 
}
int main(){
    dep[2] = dep[3] = dep[4] = 1;
    f[2][0] = f[3][0] = f[4][0] = 1, tot = 4;
    int n, l = 2, r = 4, ans = 2;
    read(n);
    for(int i = 1; i <= n; i++){
        int x; read(x);
        addson(x), addson(x);
        int nl = tot - 1, nr = tot;
        int s1 = dis(nl, r), s2 = dis(nl, l);
        int s3 = dis(nr, l), s4 = dis(nr, r);
        ans = Max(ans, Max(Max(s1, s2), Max(s3, s4)));
        if(ans == s1) l = nl;
        else if(ans == s2) r = nl;
        else if(ans == s3) r = nr;
        else if(ans == s4) l = nr;
        printf("%d\n", ans); 
    }   
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mangoyang/p/9356990.html