题意:给出一棵树,并给出每个节点上的权值,求有多少个连通子块的最大值与最小值的差不超过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\n",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\n",dp[i]); } cout << ans << endl; return 0; }
时间: 2024-10-14 12:46:42