P5007 DDOSvoid 的疑惑
题目背景
DDOSvoid 最近一直很痴迷于树形结构,尤其是可持久化喜羊羊灰太狼套红太狼树,可以 O(log)O(\log)O(log) 维护你想维护的信息。
但是这只是一个理论数据结构,为了研究其如何实现,DDOSvoid 开始思考树的父亲和儿子之间的关系。
如果这个数据结构得到实现,那么这个世界就再也没有毒瘤题了。
但毕竟这个问题太难,所以我们先考虑下面的这个问题。
题目描述
给定一棵以 111 为根的有根树,定义树的一个毒瘤集为一个集合,并且集合中任意两个元素之间不存在祖先与后代关系。
定义一个毒瘤集的毒瘤指数为集合内所有元素的价值之和。要求给定树的所有毒瘤集的毒瘤指数之和,答案对 100,000,007100{,}000{,}007100,000,007 取模。
但这个问题太难了,所以我们考虑化简。
因为点的编号跟它毒瘤指数密切相关,所以我们将会再给出一个整数 TTT:T=1T = 1T=1 表示 iii 号点的毒瘤指数为 iii;T=0T = 0T=0,表示所有点的毒瘤指数都是 111。
输入格式
第一行两个整数 nnn、TTT,表示这棵树有 nnn 个节点。
接下来 n−1n -1n−1 行,每行两个整数 xxx 和 yyy,表示有一条边,连接 xxx 和 yyy。
输出格式
输出一个整数,表示答案。
输入输出样例 #1
输入 #1
5 0
1 2
2 3
2 4
1 5
输出 #1
16
说明/提示
样例解释:
101010 个集合分别为 {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%30 \%30% 的部分分,n≤15n \le 15n≤15;
- 另外 20%20 \%20% 的部分分,n≤106n \le 10^6n≤106,T=0T = 0T=0;
- 对于 100%100 \%100% 的数据,n≤106n \le 10^6n≤106,$ T <= 1$。
为了方便你理解题意,下面给出毒瘤集的数学定义:
设一个毒瘤集为 AAA,则
- ∀i∈A\forall i\in A∀i∈A,不存在一个点 jjj,使得 jjj 在从 iii 到根节点的简单路径上,且 $ j \in A$。其中 $ i,j \in V,,,V$ 为树的点集。
C++实现
#include<iostream>
#include<algorithm>
#include<cstring>
#define maxn 1000010
#define ll long long
#define gc getchar
using namespace std;
int n, m, T;
int w[maxn];
const int p = 100000007;
int read(){
int x = 0; char c = gc();
while(!isdigit(c)) c = gc();
while(isdigit(c)){x = x * 10 + c - '0'; c = gc();}
return x;
}
struct Edge{
int to, next;
}e[maxn * 2]; int c1, head[maxn];
inline void add_edge(int u, int v){
e[c1].to = v; e[c1].next = head[u]; head[u] = c1++;
}
ll f[maxn], g[maxn];
void dfs(int u, int fa){
for(int i = head[u]; ~i; i = e[i].next){
int v = e[i].to; if(v == fa) continue;
dfs(v, u);
f[u] = (f[u] * g[v] + f[v] * g[u] + f[u] + f[v]) % p;
g[u] = (g[u] * g[v] + g[u] + g[v]) % p;
}
f[u] = (f[u] + w[u]) % p; ++g[u];
}
int main(){
memset(head, -1, sizeof head);
n = read(); T = read();
for(int i = 1; i <= n; ++i) w[i] = T ? i : 1;
for(int i = 1; i < n; ++i){
int x = read(), y = read();
add_edge(x, y); add_edge(y, x);
}
dfs(1, 0); cout << f[1] << endl;
return 0;
}

后续
接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容
3011

被折叠的 条评论
为什么被折叠?



