【题解】【CF486D Valid Sets】

发布时间:2022-07-04 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了【题解】【CF486D Valid Sets】脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

题目:CF486D Valid Sets 题目大意:给出一棵树,树上有点权,求这棵树的满足最大点权与最小点权之差小于d的连通子图的个数。 Solution: 题目既要维护最大点权,也要维护最小点权,比较难考虑;

那么我们想固定其中一个极值,这样只需考虑另一个就行了,以最小值为例:如果我们确定一个点为联通子图的最小点,那么我们可以以这个点为根做一个树形dp,统计包含这个点,且满足最大值与这个点的差小于等于d,且这个点在子图中最小的子图个数。总复杂度为O(N^2)

对于两个点相等的情况,还要考虑避免重复,有两种处理方法: 一是固定只能从编号小的点走到编号大的点, 二是在dp中若遇到与根节点相等的点,检查这个点是否当过根节点,若是,不再计算;

#include<bITs/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
	register int x=0,w=1;
	register char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {ch=getchar();w=-1;}
	while(ch>='0'&amp;&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();	}
	return x*w;
}
const int N=2005,mod=1e9+7;
int n,d,val[N],f[N];
struct node{
	int nxt,to,w;
}e[N<<2];
vector<int>v[N];
int root,vis[N],fa[N];
void dp(int x)
{
	f[x]=1;
	for(int i=0;i<v[x].size();++i)
	{
		int y=v[x][i];
		if(y==fa[x]) continue;
		fa[y]=x;
		if(val[y]==val[root]&&vis[y]) continue;
		if(val[y]<val[root]) continue;
		if(abs(val[y]-val[root])>d) continue;
		dp(y);
		f[x]*=f[y]; 
		f[x]%=mod;
	}
	f[x]++;
}
int ans;
signed main()
{
    d=read();n=read();
    for(int i=1;i<=n;++i) val[i]=read();
    for(int i=1;i<n;++i){
    	int x,y;
    	x=read();y=read();
    	v[x].push_back(y);
    	v[y].push_back(x);
	}
	for(int i=1;i<=n;++i)
	{
		root=i;
		dp(i);
		ans+=f[root]-1;
		ans%=mod;
		vis[root]=1;
		memset(fa,0,sizeof fa);
	}
	cout<<ans<<endl;
	return 0;
}
/*
6 6
8 5 5 8 6 5 
2 1
3 1
4 1
5 4
6 1
*/

脚本宝典总结

以上是脚本宝典为你收集整理的【题解】【CF486D Valid Sets】全部内容,希望文章能够帮你解决【题解】【CF486D Valid Sets】所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。