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 */