Description
科学家在观测一棵大树,这棵树在不断地生长,科学家给这棵树的每个节点编了号。开始的时候,这棵树很小只有4个节点,一号点为根,其他三个节点挂在上面。
在接下来的M次观察中,科学家每次都能看见这棵树从叶子处长出新的两个节点来。如果当前这棵树有N个节点,那么这棵树的新的两个节点的编号分别为N+1,N+2。科学家记录下了这棵树生长的过程,需要你帮着计算这棵树实时的直径。树的直径就是这棵树最远的两个节点的距离。
Input
第一行一个整数M,代表观察的次数。
接下来M行,每行一个整数x,代表这棵树的编号为x的节点下面又长了两个叶子节点。保证每次生长的节点都是叶子节点。
Output
M行,每次生长后这棵树的直径。
Sample Input
5
2
3
4
8
5
Sample Output
3
4
4
5
6
Data Constraint
对于10%的数据,N<=10
对于40%的数据,N<=1000
对于100%的数据,N<=100000。
Solution
首先要发现一个性质,新直径的两端必定在有一个端点在旧直径上。
之后就可以先离线把所有点都增加好,建一棵树,记录一下每一轮新增加的点是哪两个。
然后倍增一下求lca再算两点路径就可以了。
Code(Pascal)
type new=record
x,y:longint;
end;
var n,i,j,l1,r1,l,r,s,tot,x,cnt,s1,t:longint;
h,fa,next,head,b:array [0..250000] of longint;
anc:array [0..200500,0..18] of longint;
a:array [0..100050] of new;
procedure add(x,y:longint);
begin
inc(tot);
next[tot]:=head[x];
head[x]:=tot;
b[tot]:=y;
end;
procedure dfs(x:longint);
var i,j:longint;
begin
anc[x,0]:=fa[x];
for i:=1 to 18 do anc[x,i]:=anc[anc[x,i-1]][i-1];
i:=head[x];
while i<>0 do begin
j:=b[i];
if j<>fa[x] then begin
fa[j]:=x;
h[j]:=h[x]+1;
dfs(j);
end;
i:=next[i];
end;
end;
function lca(x,y:longint):longint;
var i:longint;
begin
if h[x]<h[y] then begin
i:=x; x:=y; y:=i;
end;
for i:=18 downto 0 do if h[anc[x,i]]>=h[y] then x:=anc[x,i];
if x=y then exit(x);
for i:=18 downto 0 do
if (anc[x,i]<>anc[y,i]) then begin
x:=anc[x,i];
y:=anc[y,i];
end;
exit(anc[x,0]);
end;
begin
readln(n);
add(1,2);
add(1,3);
add(1,4);
cnt:=4;
for i:=1 to n do begin
read(x);
inc(cnt);
a[i].x:=cnt;
add(x,cnt);
inc(cnt);
a[i].y:=cnt;
add(x,cnt);
end;
fa[1]:=1;
h[1]:=1;
dfs(1);
l:=2; r:=4; s:=2;
for i:=1 to n do begin
t:=lca(l,a[i].x);
s1:=h[l]+h[a[i].x]-2*h[t];
if s1>s then begin
l1:=l; r1:=a[i].x;
s:=s1;
end;
t:=lca(r,a[i].x);
s1:=h[r]+h[a[i].x]-2*h[t];
if s1>s then begin
l1:=a[i].x; r1:=r; s:=s1;
end;
t:=lca(l,a[i].y);
s1:=h[l]+h[a[i].y]-2*h[t];
if s1>s then begin
l1:=l; r1:=a[i].y; s:=s1;
end;
t:=lca(r,a[i].y);
s1:=h[r]+h[a[i].y]-2*h[t];
if s1>s then begin
l1:=r; r1:=a[i].y; s:=s1;
end;
writeln(s);
l:=l1; r:=r1;
end;
end.