【题解】【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