【CF379F】New Year Tree

题目

题目链接:https://codeforces.com/problemset/problem/379/F
有一颗 \(4\) 个节点的树,\(2,3,4\) 号节点的父亲节点都是 \(1\)\(m\) 次操作。操作有 \(1\) 种:

  • u:设现在这颗树有 \(n\) 个节点,则您要新建两个节点 \(n+1,n+2\) 并让它们变为 \(u\) 的儿子节点(连一条 \(u\)\(n+1\) 的边和 \(u\)\(n+2\) 的边)。保证 \(u\) 是叶子节点。进行完操作后,您要输出此时树的直径。

\(1\le m\le 5\times 10^5\)

思路

首先每次操作最多只会让直径增加 \(1\)。那么如果原来直径两端是 \(x,y\),这次加入点后直径增加了,那么 \(x,n+1\)\(y,n+1\) 中至少有一个会成为新的直径两端。
所以只需要倍增求一下 LCA 就可以了。
时间复杂度 \(O(m\log m)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=1000010,LG=20;
int m,x,y,f[N][LG+1],dep[N];

int lca(int x,int y)
{
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=LG;i>=0;i--)
		if (dep[f[x][i]]>=dep[y]) x=f[x][i];
	if (x==y) return x;
	for (int i=LG;i>=0;i--)
		if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}

int dis(int x,int y)
{
	int p=lca(x,y);
	return dep[x]+dep[y]-2*dep[p];
}

int main()
{
	scanf("%d",&m);
	f[2][0]=f[3][0]=f[4][0]=1;
	dep[2]=dep[3]=dep[4]=2; dep[1]=1;
	x=2; y=3;
	for (int i=1,n=5,u;i<=m;i++,n+=2)
	{
		scanf("%d",&u);
		f[n][0]=f[n+1][0]=u;
		dep[n]=dep[n+1]=dep[u]+1;
		for (int i=1;i<=LG;i++)
			f[n][i]=f[n+1][i]=f[f[n][i-1]][i-1];
		if (dis(x,y)<dis(x,n)) y=n;
		if (dis(x,y)<dis(y,n)) x=n;
		cout<<dis(x,y)<<"\n";
	}
	return 0;
}
posted @ 2021-11-07 17:27  stoorz  阅读(34)  评论(0编辑  收藏  举报