其他分享
首页 > 其他分享> > 【题解】【CF486D Valid Sets】

【题解】【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'&&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
*/

标签:ch,int,题解,点权,read,Valid,Sets,dp,getchar
来源: https://www.cnblogs.com/glq-Blog/p/15362418.html