一、题目
二、解法
回忆树直径的非 d p dp dp求法,随便那一个点找到最远点,再从最远点找它的最远点就得到了直径。
这道题肯定不能暴力找,我们考虑新加入的点对直径的影响,设原来的直径端点是 ( A , B ) (A,B) (A,B),算出新加入点为直径端点时的直径和原来的直径比较就知道他是不是直径的端点。而新加入点的最远点是谁呢?因为他父亲的最远点是 A / B A/B A/B,所以他的最远点也是 A / B A/B A/B,两种情况都考虑一下就行了,最后写一个倍增 l c a lca lca即可。
#include <cstdio>
#include <iostream>
using namespace std;
const int M = 1000005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,A,B,len,dep[M],fa[M][20];
void upd(int x,int p)
{
fa[x][0]=p;
dep[x]=dep[p]+1;
for(int i=1;i<=19;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int i=19;i>=0;i--)
if(dep[fa[u][i]]>=dep[v])
u=fa[u][i];
if(u==v) return u;
for(int i=19;i>=0;i--)
if(fa[u][i]^fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
int dis(int u,int v)
{
return dep[u]+dep[v]-2*dep[lca(u,v)];
}
signed main()
{
n=4;m=read();
upd(2,1);
upd(3,1);
upd(4,1);
A=2;B=3;len=2;
while(m--)
{
int x=read();
upd(++n,x);
upd(++n,x);
if(dis(A,n)>len)
{
len=dis(A,n);
B=n;
}
if(dis(n,B)>len)
{
len=dis(n,B);
A=n;
}
printf("%d\n",len);
}
}