森林 [树的直径]

森林


\color{red}{正解部分}

考虑在加节点时维护 直径 u,vu, v, 和距离 直径 最远的点 ss, 在询问时直接将 ss链 截到直径端点即可 .
在加入一个节点 xx 时, 这个节点可能会替代 u,vu,v, 或者替代 ss,


注意在计算 ss 离直径距离 时需要留心 ss 是否在 直径lca 下面, 计算方式不同 .


\color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 2e5 + 10;

int N;
int u;
int v;
int s;
int Len;
int dep[maxn];
int Fk[maxn][20];

int Lca(int x, int y){
        if(dep[x] < dep[y]) std::swap(x, y);
        for(reg int i = 19; i >= 0; i --) 
                if(dep[Fk[x][i]] >= dep[y]) x = Fk[x][i];
        if(x == y) return x;
        for(reg int i = 19; i >= 0; i --)
                if(Fk[x][i] != Fk[y][i]) x = Fk[x][i], y = Fk[y][i];
        return Fk[x][0];
}

int Dis(const int &x, const int &y){ return dep[x] + dep[y] - (dep[Lca(x, y)] << 1); }

int Dis_2(int x){
        int lca = Lca(u, v);
        if(Lca(lca, x) == lca) return std::min(Dis(Lca(x, u), x), Dis(Lca(x, v), x));
        return Dis(lca, x);
}

void Add(int fa, int x){
        Fk[x][0] = fa; dep[x] = dep[fa] + 1;
        for(reg int i = 1; i <= 19; i ++) Fk[x][i] = Fk[Fk[x][i-1]][i-1];
        if(Dis(x, u) < Dis(x, v)) std::swap(u, v);
        int t = Dis(x, u);
        if(Len < t) Len = t, std::swap(x, v);
        if(Dis_2(x) > Dis_2(s)) s = x;
}

int main(){
        read(); N = read(); dep[1] = 1;
        u = v = s = 1;
        int last_ans = 0;
        for(reg int i = 2; i <= N; i ++){
                int a = read() ^ last_ans;
                Add(a, i);
                printf("%d\n", last_ans = Len + std::max(Dis_2(s)-1, 0));
        }
        return 0;
}
posted @   XXX_Zbr  阅读(144)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示