codeforces486D Valid Sets 树上计数

题目链接:戳这里

题目大意:给出一棵树,树上有点权,求这棵树的满足最大点权与最小点权之差小于d的连通子图的个数。

题解:我们可以枚举一个点作为最大的点权向下扩展。但这样有一个问题:点权相等的点会重复扩展。所以我们规定点权相等的点,只能由编号小的向编号大的点扩展。

代码:

#include<bits/stdc++.h>
#define maxn 200005
#define maxm 400005
#define mod 1000000007
using namespace std;
typedef long long LL;
int read()
{
	char c;int sum=0,f=1;c=getchar();
	while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}
	return sum*f;
}
int n,d;
int head[maxn],to[maxm],nex[maxm],val[maxn],cnt;
void add(int u,int v)
{
	to[++cnt]=v;nex[cnt]=head[u];head[u]=cnt;
}
LL ans;
LL dfs(int x,int fa,int lim)
{
	LL ret=1;
	for(int i=head[x];i;i=nex[i])
	{
		if(to[i]==fa || val[to[i]]>val[lim] || (val[to[i]]==val[lim] && to[i]>lim) || val[lim]-val[to[i]]>d)
		continue;
		ret=ret*(dfs(to[i],x,lim)+1)%mod;
	}
	return ret;
}
int main()
{
	d=read();n=read();
	for(int i=1;i<=n;i++) val[i]=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		add(u,v);add(v,u);
	}
	for(int i=1;i<=n;i++)
	ans+=dfs(i,-1,i),ans%=mod;
	cout<<ans<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39791208/article/details/79345609
今日推荐