Codeforces Round #277 (Div. 2)D题

As you know, an undirected connected graph with n nodes and n - 1 edges is called a tree. You are given an integer d and a tree consisting of n nodes. Each node i has a value ai associated with it.

We call a set S of tree nodes valid if following conditions are satisfied:

  1. S is non-empty.
  2. S is connected. In other words, if nodes u and v are in S, then all nodes lying on the simple path between u and v should also be presented in S.
  3. .

Your task is to count the number of valid sets. Since the result can be very large, you must print its remainder modulo 1000000007(109 + 7).

Input

The first line contains two space-separated integers d (0 ≤ d ≤ 2000) and n (1 ≤ n ≤ 2000).

The second line contains n space-separated positive integers a1, a2, ..., an(1 ≤ ai ≤ 2000).

Then the next n - 1 line each contain pair of integers u and v (1 ≤ u, v ≤ n) denoting that there is an edge between u and v. It is guaranteed that these edges form a tree.

Output

Print the number of valid sets modulo 1000000007.

Sample test(s)
input1
1 4
2 1 3 2
1 2
1 3
3 4
output1
8
input2
0 3
1 2 3
1 2
2 3
output2
3
input3
4 8
7 8 7 5 4 6 4 10
1 6
1 2
5 8
1 3
3 5
output3
41
题目大意:给你一棵无根树,节点带权值,给你一个d。要求满足条件的子树有多少个。条件1:子树不为空;条件:2:子树中权值最大-权值最小<=d。
题目分析:。。。见题太少,一时无从下手。正解:由于要使 子树中权值最大-权值最小<=d,我们枚举每一个节点,然后以此为根节点宽搜遍历出子树,并要求此点是子树中的权值最小的点。然后只要遍历时遇到分叉点就将所有分叉的情况相乘就可以了。
PS:当遍历到节点权值和当前遍历的根节点权值相等的话会出现重复计算的子树!这里只要在以编号小的节点为根节点时加入不管这种情况,当以编号大的节点碰到这种情况就退出当前遍历,这样处理得话就能让权值相等的只计算一次~

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int inf = (1<<31)-10;
const int MOD = (1e9)+7;
vector<int>tree[2010];
int d,a[2010],q[2010],f[2010];
void dfs(int x,int root)
{
    int i,j;
    q[x]=1;f[x]=1;
    for (i=0;i<tree[x].size();i++)
        if (!q[tree[x][i]]) {
            if (a[root]>a[tree[x][i]]||a[tree[x][i]]>a[root]+d) continue;
            if (a[root]==a[tree[x][i]]&&tree[x][i]<root) continue;///判重!
            dfs(tree[x][i],root);
            f[x]=((long long)f[x]*(f[tree[x][i]]+1))%MOD;///递归求当前节点的数值。
        }
}
int main()
{
    int i,j,n,u,v,ans=0;
    scanf("%d%d", &d, &n);
    for (i=1;i<=n;i++) scanf("%d", &a[i]);
    for (i=1;i<n;i++) {
        scanf("%d%d", &u, &v);
        tree[u].push_back(v);
        tree[v].push_back(u);
    }
    for (i=1;i<=n;i++) {
        for (j=1;j<=n;j++) {
            f[j]=0;q[j]=0;
        }
        dfs(i,i);///以每一个节点作为最小节点(根)遍历。
        ans=(ans+f[i])%MOD;
    }
    printf("%d\n", ans);
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值