CF690C3 Brain Network (hard) 题解

题目大意

一棵树,每次加一个节点,并且询问每次加后的树的直径

解题思路

可以知道,每次加点后最多对树的直径的影响为 \(1\) 。而且有一个重要性质:加进的这个叶子如果能对答案产生贡献,那么这个叶子和原来直径一定有公共端点,所以我们求出每个状态下的 \(u和v和ans\) ,每次要么不更新,要么只更新一个节点。判断是否需要更新需要求 \(lca\) 所以可以先预处理,再加边。

\(code\)

#include <bits/stdc++.h>
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
const int maxn=200030;
int n,to[maxn],nxt[maxn],head[maxn],num;
void add(int x,int y){num++;nxt[num]=head[x];to[num]=y;head[x]=num;}
int dep[maxn],fa[maxn],son[maxn],siz[maxn],top[maxn],ans,u,v;
void dfs_build(int p,int F)
{
    siz[p]=1;
    fa[p]=F;
    dep[p]=dep[F]+1;
    for(int i=head[p];i;i=nxt[i])
    {
        if(to[i]!=F)
        {
            dfs_build(to[i],p);
            siz[p]+=siz[to[i]];
            if(siz[to[i]]>siz[son[p]])
                son[p]=to[i];
        }
    }
}
void dfs_create(int p,int tp)
{
    top[p]=tp;
    if(son[p])dfs_create(son[p],tp);
    for(int i=head[p];i;i=nxt[i])
    {
        if(to[i]!=son[p]&&to[i]!=fa[p])
            dfs_create(to[i],to[i]);
    }
}
int Lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    return x;
}
bool judge(int u,int v)
{
	int l=Lca(u,v);
	int ss=dep[u]+dep[v]-2*dep[l];
	if(ss>ans)
	{ans=ss;return 1;}
	return 0;
}
int main()
{
	n=read();
	for(int i=2;i<=n;i++)
	{
		fa[i]=read();
		add(fa[i],i);
	}
	dfs_build(1,1);dfs_create(1,1);
	u=v=1;ans=0;
	for(int i=2;i<=n;i++)
	{
		int ls=v;
		if(judge(u,i))	ls=i;
		if(judge(v,i))
		{
			u=v;
			ls=i;
		}
		v=ls;
		printf("%d ",ans);
	}
	return 0;
}
上一篇:Codeforces Round #741 (Div. 2) D. Two Hundred Twenty One (easy & hard version)(思维 + 前缀和)


下一篇:CodeForces 1551D2 : Domino (hard version) 模拟