CF1695D2 Tree Queries (Hard Version)

原题

翻译

被xjk搏杀了,wtcl

先说以下自己的思路,xjk提出让我手玩一下样例,发现确实挺有用的

image.png

我们看这个2是怎么来的,我们发现有一种答案是选{5,8},我们发现不能选{5,10}的原因是我们无法确定89的区别

于是我想如果一种选点的方案不可行,当且仅当存在两个节点x,y,使得这两个点到所有关键点的距离是一样的

感性理解一下,如果x移动的距离很多的话,反而是不于出现不同的距离。因此我考虑如果xu移动到他的兄弟,会对距离产生什么样的影响

如样例,当x=8的时候,我们让他移动到9,显然会让以8为根的子树内所有关键点+2,让以9为根的子树内所有关键点2

于是我们发现对于一个点u延伸出来的所有点的子树,如果有超过2个点的子树内没有关键点,那这些点内所有关键点到他们的距离是一样的,不符合题意

因此原问题就变成了考虑树上所有点连向的点中最多只有一个点的子树内没有关键点,最少可以放多少关键点

然后这个问题就做不下去了233


xjk的思路是这样:

首先,绝对显然的是这些关键节点在叶子上,否则一定不优

我们发现,如果选择两个节点(x,y),则我们可以确定xy的这条路径上的所有点 和 这些点向外延伸出来的

因为我们考虑如果dx+dydist(x,y),则我们显然可以唯一确定这个点

否则,我们可以找到一个最大的d,满足dxd+dyddist(x,y),这样我们可以通过dxddyd唯一确定这个点和路径的交点,再通过d确定他在这条链上的深度

例如样例,我们如选择了5,10,则我们可以确定的点为{5,7,4,2,1,3,10,6},但{8,9}显然不能被确定,因为我们无法通过延伸点的编号和深度来唯一确定这两个点

我们发现链不好考虑,而且是没有必要的,因此我们先把所有的链缩成一条边,最后得到的图中每个点要么度数>2,要么是叶子节点

容易想到这么建了一棵新树后对于每个点的所有儿子,必然最多只有一个儿子内没有关键点;于是我们贪心的选择,让每一个儿子就只有li1个关键点

于是我们有以下计算方案:对于每一个点,记新图中与它直接相连的叶子个数为li,则这个点对答案的贡献为max(li1,0)

这个做法正确的原因是对于每个节点,与它相连的非叶子节点一定已经在枚举它时都被考虑过,因此我们只用考虑对于li个叶子节点选li1个即可

如果我们用set维护树,并直接构造新树,则做法是O(nlogn)的,并不非常优秀,参见题解。他的代码第41,42行写的很奇怪,是可以直接写成:

for(int i=1;i<=n;i++){
	d[i]-=(int)E[i].size();
	//如果在新树上度为 1,那就是其中一条上出边,与一条连到附属点的边虚化
	//否则减新树上所有出边
	if(!vis[i])ans+=max(d[i]-1,0);//还有剩下的附属点
}

的,阅读的时候要注意一下。


我们考虑一下怎么优化

我们发现其实我们并不需要直接把新树建出来,因为我们发现对于原树的每个叶子,把他沿着一条链暴力上传,直到上传到degu3的点后,把贡献加到点u上即可,复杂度显然是便利整棵树

个人实现的时候是在树上找了一个degu3的点作为dfs时的根,在dfs中维护每个点的父亲;因为degroot3,因此叶子节点不会超过这个节点再跑下去。而如果找不到一个degu3的点,显然就是一条链,直接输出1即可

最终复杂度O(n)

posted @   FOX_konata  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示