CF1039D You Are Given A Tree

题目传送门:CF1039D

洛谷入口

题目大意:

(给出一棵n个节点的树,对于的每一个数kin{[1,n]},你需要求出:)
(最多能选出多少条互不相交的路径,每条路径的长度都为k)

数据范围

(circ) (nle10^5)

题解

这题的题意相信大家都能看懂
对于一个数(kin{[1,n]})
只看他,我们要思考一种方法去覆盖树
其实如果去思考dfs时
会发现对于一个点u
只要u的众多子链(就是只由u的子节点们构成的一条链)
其中最长的和次长的再加上u本身
就能拼成可以DP不相互影响的一种路径
如果这路径长度可以达到规定的k
则可以把答案++,再把u记录的链长记为0表示已消耗
这样就可以计算出对于一个k的答案
好了完结了(没有)
我们会出现一个问题,这样一遍dfs复杂度是(O(n))
那么每一个要n,总共就要(O(n^2))了!
(10^{10})——神仙也救不了
所以要思考答案的特性
我们都知道:k越大,答案不可能更大
且会发现答案不同的最多只有(sqrt n)种(证明我也不好说明)
所以可以去找一下答案相同的区间([l,r])再统一赋值
这样可以去思考二分
让mid的答案把可能性一个个限制住
就渐渐达到了上述要求
就没了!这题结束了!然后上代码↓↓↓

AC代码

//渐渐省略不必要的东西——头文件
int tot,cnt,n,k,head[100010],dp[100010],d[100010];
struct abc{
	int to,nxt;
}e[300010];
//渐渐省略不必要的东西*2——链式前向星
void dfs(int u,int fa,int ya){
	int f=0,s=0;
	d[u]=0;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa)continue;
		dfs(v,u,ya);
		if(f<d[v])s=f,f=d[v];
		else if(s<d[v])s=d[v];
	}
	if(f+s>=ya-1)tot++,d[u]=0;
	else d[u]=f+1;
}
void dou(int l,int r,int zu,int yo){
	if(l>r||zu>yo)return;
	if(zu==yo){
		for(int i=l;i<=r;i++)dp[i]=zu;
		return;
	}
	int mid=l+r>>1;
	tot=0;
	dfs(1,0,mid);
	dp[mid]=tot;
	dou(l,mid-1,tot,yo);
	dou(mid+1,r,zu,tot);
}
//渐渐省略一些不必要的东西*3——主函数

支持一下吧,关注,点赞,评论都好!

THE END

Reality&Imagine
原文地址:https://www.cnblogs.com/yang-RA-NOI/p/12594662.html