题意:n个结点的树,m种颜色,求每种颜色中距离最远的两点的距离
易知,距离最远的两点中一定有一个点是该颜色深度最深的点,另一个枚举求lca更新即可
小机智:求出每种颜色深度最深的点后,枚举颜色再枚举结点更新该颜色的答案显然是会吃TLE的,所以我们枚举n个结点,判断每个节点对它所属于的颜色是否能更新,这样降下了复杂度
var
n,m,l,x,tt,root :longint;
i,j :longint;
vis :array[0..200010] of boolean;
a,d,last :array[0..200010] of longint;
ans,maxn :array[0..100010] of longint;
pre,other,len :array[0..200010] of longint;
jump :array[0..200010,0..20] of longint;
procedure swap(var a,b:longint);
var
c:longint;
begin
c:=a; a:=b; b:=c;
end;
procedure connect(x,y:longint);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
end;
procedure dfs(x:longint);
var
p,q:longint;
begin
q:=last[x];
while (q<>0) do
begin
p:=other[q];
if not vis[p] then
begin
vis[p]:=true;
d[p]:=d[x]+1;
jump[p,0]:=x;
dfs(p);
end;
q:=pre[q];
end;
end;
function lca(x,y:longint):longint;
var
ans:longint;
i,j:longint;
begin
ans:=0;
if d[x]>d[y] then swap(x,y);
for i:=0 to 20 do
if ((d[y]-d[x]) and (1<<i) <>0) then
begin
inc(ans,1<<i);
y:=jump[y,i];
end;
//
if x=y then exit(ans);
for i:=20 downto 0 do
if jump[x,i]<>jump[y,i] then
begin
inc(ans,1<<i);
inc(ans,1<<i);
x:=jump[x,i];
y:=jump[y,i];
end;
inc(ans,2);
exit(ans);
end;
begin
read(n,m);
for i:=1 to n do
begin
read(a[i],x);
if x=0 then root:=i else connect(x,i);
end;
vis[root]:=true; d[root]:=1; dfs(root);
for j:=1 to 20 do
for i:=1 to n do jump[i,j]:=jump[jump[i,j-1],j-1];
//
for i:=1 to n do
if d[i]>d[maxn[a[i]]] then maxn[a[i]]:=i;
for i:=1 to n do
begin
tt:=lca(i,maxn[a[i]]);
if tt>ans[a[i]] then ans[a[i]]:=tt;
end;
//
for i:=1 to m do writeln(ans[i]);
end.
——by Eirlys