codeforces 442D - Adam and Tree

18 篇文章 0 订阅
8 篇文章 0 订阅

题目大意:

给一棵树上的每条边染色,每种颜色只能用一次,一次染色树上的一条链。

问(从根到所有节点经过的颜色的最大值)的最小值是多少。

树是通过每次加一个点得到的,问每次加点之后的最小值是多少。

点数<=1,000,000

不难发现,答案肯定是小于等于直接树剖的答案,也就是log当前点数。

显然能想到dp:用f[i]表示处理i的所有子树和i所需的最小颜色。如果正常染色的话,我们会尝试把f值最小的两棵子树和i染成到i的边相同的颜色,所以我们处理出m1[],m2[]表示每个节点子树f值的最大值和第二大值。那么如果m1[i]>m2[i]+1,我们就向m1[i]连边,则f[i]等于m1[i]。否则,我们把m1[i]和m2[i]链接起来,f[i]=m2[i]+1(因为此时i无法和fa[i]连接起来,答案就要+1)。

如果不考虑复杂度,那么我们直接向上暴力修改的话,每次的复杂度是O(H),H是树高。但是注意到答案相当小,也就是说N次修改,只有logN次会走到根,其他的都在半路影响就消除了。所以我们直接往上爬,如果当前点的f[i]值等于max(m2[i]+1,m1[i])就可以退出了。这是因为正常情况下f[i]=max(m2[i]+1,m1[i]),如果相等的话,就不需要修改下去了。

附代码:

#include<bits/stdc++.h>
#define N 1001000
using namespace std;
int n;
int f[N],fa[N],m1[N],m2[N];
int main(){
	scanf("%d",&n);
	for(int i=2,a;i<=n+1;i++){
		scanf("%d",&fa[i]);
		f[i]=1;
		int t=i;
		while(t!=1){
			if(f[t]>m1[fa[t]]) m2[fa[t]]=m1[fa[t]],m1[fa[t]]=f[t];
			else m2[fa[t]]=max(m2[fa[t]],f[t]);
			if(max(m2[fa[t]]+1,m1[fa[t]])==f[fa[t]]) break;
			else f[fa[t]]=max(m2[fa[t]]+1,m1[fa[t]]);
			t=fa[t];
		}
		printf("%d ",m1[1]);
	}
	puts("");
	return 0;
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值