Description
科学家在观测一棵大树,这棵树在不断地生长,科学家给这棵树的每个节点编了号。开始的时候,这棵树很小只有4个节点,一号点为根,其他三个节点挂在上面。
在接下来的M次观察中,科学家每次都能看见这棵树从叶子处长出新的两个节点来。如果当前这棵树有N个节点,那么这棵树的新的两个节点的编号分别为N+1,N+2。科学家记录下了这棵树生长的过程,需要你帮着计算这棵树实时的直径。树的直径就是这棵树最远的两个节点的距离。
Input
第一行一个整数M,代表观察的次数。
接下来M行,每行一个整数x,代表这棵树的编号为x的节点下面又长了两个叶子节点。保证每次生长的节点都是叶子节点。
Output
M行,每次生长后这棵树的直径。
Data Constraint
对于10%的数据,N<=10
对于40%的数据,N<=1000
对于100%的数据,N<=100000。
Solution
一个显然的特点就是对于原来的最长链两端点(t1,t2),新的最长链至少有一点是其中之一。即对于新增点x,我们比较(t1,x),(x,t2),(t1,t2)的长度取最长
有一种做法就是把整棵树离线然后做lca,这样求树上路径就是nlogn的了
Code
#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define N 200005
int fa[N][19],dep[N],rec[N],q[N];
int n=4,m;
void read(int &x) {
x=0; char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
}
int get_lca(int x,int y) {
if (dep[x]<=dep[y]) x^=y,y^=x,x^=y;
drp(i,18,0) if (dep[fa[x][i]]>=dep[y]) {
x=fa[x][i];
}
if (x==y) return x;
drp(i,18,0) if (fa[x][i]!=fa[y][i]) {
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
int get_dis(int x,int y) {
return dep[x]+dep[y]-dep[get_lca(x,y)]*2;
}
void add(int x) {
fa[++n][0]=x; dep[n]=dep[x]+1;
rep(i,1,18) fa[n][i]=fa[fa[n][i-1]][i-1];
}
int main(void) {
read(m);
fa[2][0]=fa[3][0]=fa[4][0]=1;
dep[1]=0; dep[2]=dep[3]=dep[4]=1;
rep(i,1,m) {
read(q[i]);
rec[i]=n+1;
add(q[i]); add(q[i]);
}
int t1=2,t2=3;
int dis1=get_dis(t1,t2);
rep(i,1,m) {
int dis2=get_dis(t1,rec[i]);
int dis3=get_dis(t2,rec[i]);
if (dis2>=dis1&&dis2>=dis3) {
t2=rec[i];
printf("%d\n",dis1=dis2);
} else if (dis3>=dis1&&dis3>=dis2) {
t1=rec[i];
printf("%d\n",dis1=dis3);
} else {
printf("%d\n",dis1);
}
}
return 0;
}