题意:
给一棵树,每个点有个权值,求最大权值-最小权值<=d的连通块个数
题解:
枚举最大权值点作为根,可以算出最小权值最小是多少,然后树形dp,每次合并两个连通块dp[u]=dp[u]+dp[u]*dp[v] (原来的方案数+加入新连通块的方案数)
树形dp中大于最大或者小于最小显然就不考虑了;
我们考虑这样计数有什么问题:两个相同权值的点当最大权值的情况,同样的连通块会算两次;
考虑怎么去重:如果v的标号>root的标号,那么就不考虑。
1 #include<bits/stdc++.h> 2 #define maxn 2005 3 #define ll long long 4 using namespace std; 5 const ll mod = 1000000007; 6 int n,d; 7 int a[maxn]; 8 struct edge 9 { 10 int to,next; 11 }e[maxn<<1]; 12 int head[maxn],p; 13 void addedge(int u,int v) 14 { 15 e[++p].to=v;e[p].next=head[u];head[u]=p; 16 } 17 ll dp[maxn]; 18 void dfs(int u,int f,int minv,int maxv,int rt) 19 { 20 dp[u]=1; 21 for(int i=head[u];i;i=e[i].next) 22 { 23 int v=e[i].to; 24 if(v==f)continue; 25 if(a[v]<minv)continue; 26 if(a[v]>maxv||(a[v]==maxv&&v<rt))continue; 27 dfs(v,u,minv,maxv,rt); 28 dp[u]=(dp[u]+dp[u]*dp[v])%mod; 29 } 30 } 31 int main() 32 { 33 scanf("%d%d",&d,&n); 34 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 35 for(int i=1;i<n;++i) 36 { 37 int u,v; 38 scanf("%d%d",&u,&v); 39 addedge(u,v); 40 addedge(v,u); 41 } 42 ll ans=0; 43 for(int u=1;u<=n;++u) 44 { 45 memset(dp,0,sizeof(dp)); 46 dfs(u,0,a[u]-d,a[u],u); 47 ans+=dp[u]; 48 ans%=mod; 49 } 50 printf("%I64d ",ans); 51 return 0; 52 }