树上路径(动态树直径)

树上路径

Description
一棵树的构造过程为:首先以1号点为根,然后依次加入2~n号点。
加入i号点时,在1~i-1点中选择一个点为f[i],将i号点与其相连接。
Yuri想要求出,每次加点之后路上的最长路径长度

Hint
动态求树的直径
记录下现在直径的两个端点i,j,加入一个点s时,如果可以更新直径,那么新直径一定是(s,j)或(s,i)
可以想当然的证明,如果是s和另一点t构成(s,t)为新直径的话,(i,j)一定不会是原树直径
所以求一下dist(s,i)和dist(s,j),如果大于直径就更新
求dist就用倍增求LCA算树上路径就好了

Code

#include<cstdio> 
#include<algorithm> 
#include<cstring> 
using namespace std; 
const int N=200010; 
int ans,n,mx,x,top; 
int dep[N],f[N][20],v[N],stk[N]; 
int LCA(int x,int y){ 
    if(dep[x]<dep[y]) swap(x,y); 
    for(int i=18;~i;i--) 
    if(dep[f[x][i]]>=dep[y]) x=f[x][i]; 
    if(x==y) return x; 
    for(int i=18;~i;i--) 
    if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 
    return f[x][0]; 
} 
int main(){ 

    scanf("%d",&n); 
    dep[1]=1; top=stk[1]=v[1]=1; 
    for(int i=2;i<=n;i++){ 
        scanf("%d",&f[i][0]); 
        for(int j=1;j<=18;j++) 
        f[i][j]=f[f[i][j-1]][j-1]; 
        dep[i]=dep[f[i][0]]+1; 
        if(v[f[i][0]]){ 
            ans++; v[i]=1; 
            for(;top;top--) v[stk[top]]=0; 
            stk[++top]=i; 
        } 
        else { 
            x=LCA(stk[1],i); 
            ans=max(dep[i]+dep[stk[1]]-2*dep[x],ans); 
            if(dep[i]==dep[stk[1]]) v[stk[++top]=i]=1; 
        } 
        printf("%d ",ans); 
    } 
    return 0; 
}
posted @ 2018-03-29 15:18  Nepenthe  阅读(881)  评论(0)    收藏  举报


删边加边,浮生建模