CF379F New Year Tree

分析:

树的直径就是每次求树中最远的两个点。

在一棵树上快速计算两两点之间的距离,可以用倍增

设现在树上最远的两个点为L和R。

若在u处加两个点,直径会+1或者不改变。

对这两个点求一下到L的距离,和到R的距离,看会不会使答案更优,如果使得答案更优,就把L,或R更新成目前的节点。

对于动态加点,直接对新加的点跑倍增即可。

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
#define ri register int
int q,dep[N],fa[N][22],L,R,ans,cnt;
vector<int> e[N];
void init()
{
    fa[2][0]=fa[3][0]=fa[4][0]=1;
    dep[2]=dep[3]=dep[4]=1;
    ans=2; L=2,R=3; cnt=4;
}
void work(int u,int ff)
{
    fa[u][0]=ff; dep[u]=dep[ff]+1;
    for(ri i=1;i<=20;++i) fa[u][i]=fa[fa[u][i-1]][i-1];
}
int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    int ret=0;
    for(ri i=20;i>=0;--i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i],ret+=(1<<i);
    if(x==y) return ret;
    for(ri i=20;i>=0;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i],ret+=(1<<(i+1));
    return ret+2;
}
int main()
{
    init();
    int q;
    scanf("%d",&q);
    while(q--){
        int x;
        scanf("%d",&x);
        e[x].push_back(++cnt); work(cnt,x);
        e[x].push_back(++cnt); work(cnt,x);
        int lc1=lca(x,L),lc2=lca(x,R);
        if(lc1+1<=ans && lc2+1<=ans) printf("%d\n",ans);
        else if(lc1+1>ans && lc2<lc1) ans=lc1+1,R=cnt,printf("%d\n",ans);
        else ans=lc2+1,L=cnt,printf("%d\n",ans); 
    }
} 
/*
5
3
5
6
10
7
10
4
6
7
9
5
*/
View Code

 

posted on 2019-11-11 20:53  rua-rua-rua  阅读(237)  评论(0编辑  收藏  举报