题目描述
给定一棵以 1 为根的有根树,定义树的一个毒瘤集为一个集合,并且集合中任意两个元素之间不存在祖先与后代关系。
定义一个毒瘤集的毒瘤指数为集合内所有元素的价值之和
要求给定树的所有毒瘤集的毒瘤指数之和,答案对 100000007 取模。
但这个问题太难了,所以我们考虑化简。
因为点的编号跟它毒瘤指数密切相关,所以我们将会再给出一个整数 T,T = 1 表示 i 号点的毒瘤指数为 i,T = 0,表示所有点的毒瘤指数都是 1
输入输出格式
输入格式:
第一行两个整数 n、T,表示这棵树有 n 个节点。
接下来 n -1 行,每行两个整数 x 和 y,表示有一条边,连接 x 和 y。
输出格式:
输出一个整数,表示答案。
输入输出样例
输入样例#1: 复制
5 0
1 2
2 3
2 4
1 5
输出样例#1: 复制
16
说明
样例解释:
10 个集合分别为 {1},{2},{3},{4},{5},{2,5},{3,4},{3,5},{3,4,5},{4,5}\{1\},\{2\},\{3\},\{4\},\{5\},\{2,5\},\{3,4\}, \{3,5\},\{3,4,5\},\{4,5\}{1},{2},{3},{4},{5},{2,5},{3,4},{3,5},{3,4,5},{4,5}
数据范围与约定
本题采用多测试点捆绑测试
对于 30 % 的部分分,n <= 15
另外 20 % 的部分分,n <= 1000000,T = 0
对于 100 % 的数据,n <= 1000000, T <= 1
为了方便你理解题意,下面给出毒瘤集的数学定义:
设一个毒瘤集为AAA,则
∀ i ∈ A\forall~i~\in~A∀ i ∈ A,不存在一个点jjj,使得jjj在从iii到根节点的简单路径上,且 j ∈ A~j~\in~A j ∈ A。其中 i,j ∈ V~i,j~\in~V i,j ∈ V,VVV为树的点集。
逆元:a / b % mod = a * b ^ (mod - 2) % mod;
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 100000007;
const int mn = 1000010;
int cnt;
int to[2 * mn], nx[2 * mn], fr[2 * mn];
void addedge(int a, int b)
{
to[cnt] = b;
nx[cnt] = fr[a];
fr[a] = cnt++;
}
ll Pow(ll a, ll b)
{
ll ans = 1;
while (b)
{
if (b & 1)
ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll val[mn], sum[mn]; // sum[i] i的子树构成的集合总数, val[i] i的子树集合的值
void dfs(int u, int fa)
{
sum[u] = 1;
for (int i = fr[u]; i != -1; i = nx[i])
{
if (to[i] == fa)
continue;
int v = to[i];
dfs(v, u);
sum[u] = sum[u] * sum[v] % mod; // 父节点子树集合总数 = 子节点们的集合总数乘积
}
for (int i = fr[u]; i != -1; i = nx[i])
{
if (to[i] == fa)
continue;
int v = to[i];
val[u] = (val[u] + val[v] * sum[u] % mod * Pow(sum[v], mod - 2) % mod) % mod;
// 每个子节点集合内的数的贡献 = 数值 * 其他同级集合数量
}
sum[u] = (sum[u] + 1) % mod; // 集合数加上自身单独成集
}
int main()
{
memset(fr, -1, sizeof fr);
int n, T;
scanf("%d %d", &n, &T);
for (int i = 1; i < n; i++)
{
int a, b;
scanf("%d %d", &a, &b);
addedge(a, b);
addedge(b, a);
}
for (int i = 1; i <= n; i++)
{
if (T == 0)
val[i] = 1;
else
val[i] = i;
} // 节点初始值
dfs(1, 0);
printf("%lld\n", val[1]);
return 0;
}