【NOIP模拟】彩色树【树形dp】【树链剖分性质】【复杂度分析】

题意:一棵初始时为空的树,依次加入 n n n 个叶结点,每次加入后询问 用若干不同颜色的路径将树边染色后 每个点到根经过的颜色数 的最大值 的最小值。

n ≤ 1 0 6 n\leq 10^6 n106

首先发现这个路径没啥用,其实就是个剖分方案。

然后我考场以为是重链剖分,瞎胡了个东西上去获得了 5 分的好成绩。

把边的颜色放在儿子上,根结点没有颜色。这样所求就是到根路径上的所有点的颜色种类,根结点特判一下。

f ( u ) f(u) f(u) 表示 u u u 为根的答案,转移时选择除一个儿子外其他儿子 + 1 +1 +1 再取 max ⁡ \max max ,显然是取 f f f 最大的,称为重儿子。

由于存在一个叫重链剖分的东西,所以这个 f ( u ) f(u) f(u) O ( log ⁡ s i z u ) O(\log siz_u) O(logsizu) 的。考虑暴力。

维护每个点的重儿子和 dp 值,插入一个叶子后暴力往上跳。如果是重儿子,直接让父亲取 max ⁡ \max max。如果不是,判下是否需要切换成重儿子,如果切换的话父亲的 dp 值修改为原来的重儿子 + 1 +1 +1。更新不了后立刻退出。

复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 1000005
using namespace std;
inline int read()
{
	int ans=0;
	char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
int fa[MAXN],dp[MAXN],mx[MAXN];
int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	int n=read();
	puts("0");
	for (int u=2;u<=n;u++)
	{
		fa[u]=read();
		dp[u]=1;
		for (int i=u;i>1;i=fa[i]) 
			if (fa[i]==1) dp[1]=max(dp[1],dp[i]);
			else
				if (i==mx[fa[i]])
				{
					if (dp[i]>dp[fa[i]]) ++dp[fa[i]];
					else break;
				}
				else
				{
					if (!mx[fa[i]]) mx[fa[i]]=i;
					else if (dp[i]==dp[fa[i]]) dp[fa[i]]=dp[mx[fa[i]]]+1,mx[fa[i]]=i;
					else break;
				}
		printf("%d\n",dp[1]);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值