Codeforces Round #277 (Div. 2)Valid Sets 树DP

题意:给出一棵树,并给出每个节点上的权值,求有多少个连通子块的最大值与最小值的差不超过d。

对于每个顶点建立一颗树,然后找比它价值大的   或者   价值相等且之前没有被当作顶点建立树的点,这样就避免重复了。

dp[x]表示包涵x且以x为顶点的连通子树的个数,dp[x] = ∏ (dp[son[x]] + 1)。

注意要用long long 。

#include<iostream>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef long long LL;
LL d;
const LL maxn = 2222;
const LL mod = 1000000007;
struct Node
{
    LL next; LL to;
}e[maxn * 2];
LL len;
LL head[maxn];
LL dp[maxn];
LL father[maxn];
LL vis[maxn];

void add(LL from, LL to)
{
    e[len].to = to;
    e[len].next = head[from];
    head[from] = len++;
}

void build(LL root, LL pre)
{
    father[root] = pre;
    for (LL i = head[root]; i != -1; i = e[i].next){
        LL cc = e[i].to;
        if (cc == pre) continue;
        build(cc, root);
    }
}
LL val[maxn];

void dfs(LL x, LL root)
{
    dp[x] = 0; LL ans = 1;
    for (LL i = head[x]; i != -1; i = e[i].next){
        LL cc = e[i].to;
        if (cc == father[x])continue;
        if (val[cc] == val[root] && vis[cc]) continue;
        if (val[cc]<val[root] || val[cc] - val[root]>d) continue;
        //  prLLf("%I64d %I64d
",cc,val[cc]);system("pause");
        dfs(cc, root);
        ans *= dp[cc] + 1; ans %= mod;
    }
    dp[x] += ans; dp[x] %= mod;
}

int main()
{
    LL n;
    cin >> d >> n;
    len = 0;
    memset(head, -1, sizeof(head));
    memset(vis, 0, sizeof(vis));
    for (LL i = 1; i <= n; i++)
        scanf("%I64d", &val[i]);
    for (LL i = 1; i<n; i++){
        LL a; LL b;
        scanf("%I64d%I64d", &a, &b);
        add(a, b); add(b, a);
    }
    LL ans = 0;
    for (LL i = 1; i <= n; i++){
        build(i, i); dfs(i, i);
        ans += dp[i]; vis[i] = 1;
        ans %= mod;
        //  prLLf("%I64d
",dp[i]);
    }
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/yigexigua/p/4097927.html