NC19782 Tree
题目
题目描述
修修去年种下了一棵树,现在它已经有n个结点了。
修修非常擅长数数,他很快就数出了包含每个点的连通点集的数量。
澜澜也想知道答案,但他不会数数,于是他把问题交给了你。
输入描述
第一行一个整数 \(n (1≤ n ≤ 10^6)\) ,接下来n-1行每行两个整数 \(a_i,b_i\) 表示一条边 \((1≤ a_i,b_i≤ n)\) 。
输出描述
输出n行,每行一个非负整数。第i行表示包含第i个点的连通点集的数量对 \(10^9+7\) 取模的结果。
示例1
输入
6
1 2
1 3
2 4
4 5
4 6
输出
12
15
7
16
9
9
题解
知识点:树形dp,计数dp。
一道树形dp,注意到要求每个点的贡献,因此需要二次扫描+换根。
第一次先随便选个点,这里考虑以 \(1\) 为根开始dp。设 \(dp[u]\) 表示 \(u\) 为根的子树中过 \(u\) 的连通点集数量,转移方程为:
\]
表示合并以子节点 \(v\) 为根的子树的方案数,加一是不选 \(v\) 这个子树的一种可能,乘法原理合并。
第二次,在得到了各个子树答案后,可以顺推完整答案。设 \(f[u]\) 表示过 \(u\) 的连通点集数量,转移方程为:
\]
表示从父节点的答案 \(ans[u]\) 删去选或不选 \(v\) 这一支路选的答案 \(dp[v]+1\) ,再加上不选父节点 \(u\) 的答案一种,与 \(v\) 支路的答案进行乘法原理合并,最终得到 \(v\) 的完整答案 \(ans[v]\) ,其中需要求 \(dp[v]+1\) 的逆元。
但有个大坑,\(dp[v]+1 \equiv 0 \quad (\mod 10^9+7)\) 时是没有逆元的,这时候只能重新求一遍 \(\frac{ans[u]}{dp[v]+1}\) 。
如果重新开始求,把 \(u\) 作为根节点再求一次 \(dp[u]\) ,这样复杂可能会退化到枚举根的程度。
因此,考虑设 \(f[v] = \frac{ans[u]}{dp[v]+1}\) ,于是 \(ans[v] = dp[v] \cdot (f[v]+1)\) ,\(f[v]\) 可以在每次求 \(ans[v]\) 前先求出。如果 \(dp[v]+1\) 有逆元 \((dp[v]+1)^{-1}\) ,则 \(f[v] = ans[u] \cdot (dp[v]+1)^{-1}\) ;如果没有,则 \(f[v] = \frac{ans[u]}{dp[v]+1} = \frac{dp[u] }{dp[v]+1} \cdot (f[u]+1)\) ,其中 $ \dfrac{dp[u] }{dp[v]+1}$ 只需要求一遍 \(\prod (dp[v_i]+1),v_i \not= v\) 。注意初始时 \(f[1] = 0\) ,因为此时 \(ans[1] = dp[1]\) 。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
struct Graph {
int n;
struct edge {
int to, nxt;
};
vector<edge> e;
vector<int> h;
explicit Graph(int _n) :n(_n), h(_n + 1, -1) {}
void add(int u, int v) {///加边
e.push_back(edge{ v,h[u] });///边结束节点,边出发节点的上一条边在e中下标,边权
h[u] = e.size() - 1;///上一条边的下标
}
};
Graph g(1000007);
ll dp[1000007], f[1000007];
ll qpow(ll a, ll k) {
ll ans = 1;
while (k) {
if (k & 1) ans = ans * a % mod;
k >>= 1;
a = a * a % mod;
}
return ans;
}///求逆元,但得到0时代表没有逆元,因此要重新求
void dfs1(int u, int fa) {
dp[u] = 1;
for (int i = g.h[u];~i;i = g.e[i].nxt) {
int v = g.e[i].to;
if (v == fa) continue;
dfs1(v, u);
dp[u] = dp[u] * (dp[v] + 1) % mod;
}
}///处理出子树中过根节点的答案dp[u]
void dfs2(int u, int fa) {
for (int i = g.h[u];~i;i = g.e[i].nxt) {
int v = g.e[i].to;
if (v == fa) continue;
int inv = qpow(dp[v] + 1, mod - 2);
if (inv) f[v] = dp[v] * (f[u] * inv % mod + 1) % mod;///inv可以用
else {
int tmp = 1;
for (int j = g.h[u];~j;j = g.e[j].nxt) {
int vt = g.e[j].to;
if (vt == fa || vt == v) continue;
tmp = tmp * (dp[vt] + 1) % mod;
}
f[v] = dp[v] * (tmp + 1) % mod;
}///不能用就重新算一下f[u]/(dp[v]+1)
dfs2(v, u);
}
}///通过上一次处理的答案dp[u],求出完整答案f[v] = dp[v] * (f[u]/(dp[v]+1) + 1)
///表示自己子树的答案与父节点除了自己的答案加上不选父节点的答案相互匹配
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1;i < n;i++) {
int u, v;
cin >> u >> v;
g.add(u, v);
g.add(v, u);
}
dfs1(1, 0);
f[1] = dp[1];///初始化
dfs2(1, 0);
for (int i = 1;i <= n;i++) cout << f[i] << '\n';
return 0;
}
NC19782 Tree的更多相关文章
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...
- SAP CRM 树视图(TREE VIEW)
树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...
- 无限分级和tree结构数据增删改【提供Demo下载】
无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...
- 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>
在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...
- Leetcode 笔记 110 - Balanced Binary Tree
题目链接:Balanced Binary Tree | LeetCode OJ Given a binary tree, determine if it is height-balanced. For ...
- Leetcode 笔记 100 - Same Tree
题目链接:Same Tree | LeetCode OJ Given two binary trees, write a function to check if they are equal or ...
- Leetcode 笔记 99 - Recover Binary Search Tree
题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...
- Leetcode 笔记 98 - Validate Binary Search Tree
题目链接:Validate Binary Search Tree | LeetCode OJ Given a binary tree, determine if it is a valid binar ...
- Leetcode 笔记 101 - Symmetric Tree
题目链接:Symmetric Tree | LeetCode OJ Given a binary tree, check whether it is a mirror of itself (ie, s ...
- Tree树节点选中及取消和指定节点的隐藏
指定节点变色 指定节点隐藏 单击节点 未选中则选中该节点 已选中则取消该节点 前台: 1.HTML <ul id="listDept" name="listDept ...
随机推荐
- 结合SK和ChatGLM3B+whisper+Avalonia实现语音切换城市
结合SK和ChatGLM3B+whisper+Avalonia实现语音切换城市 先创建一个Avalonia的MVVM项目模板,项目名称GisApp 项目创建完成以后添加以下nuget依赖 <Pa ...
- printf 函数格式控制
Printf()介绍 printf()是C语言标准库函数,用于将格式化后的字符串输出到标准输出.标准输出,即标准输出文件,对应终端的屏幕.printf()申明于头文件stdio.h. 函数原型: in ...
- Git-签名-user-email
- 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.12.20)
一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...
- [转帖]快速入门:在 Red Hat 上安装 SQL Server 并创建数据库
https://learn.microsoft.com/zh-cn/sql/linux/quickstart-install-connect-red-hat?view=sql-server-linux ...
- [转帖]《Linux性能优化实战》笔记(十五)—— 磁盘IO的工作原理
前一篇介绍了文件系统的工作原理,这一篇来看看磁盘IO的工作原理 一. 磁盘 1. 按存储介质分类 磁盘是可以持久化存储的设备,根据存储介质的不同,常见磁盘可以分为两类:机械磁盘和固态磁盘. 机械磁盘, ...
- jcmd的简要分析命令
jcmd的简要分析命令 背景 端午加班一整天. 回到家同事让他们抓取一下堆栈信息好进行分析 连上VPN后就进行了一下处理. 自己简单看了下堆栈的总数等信息. 同事使用工具进行了分析. 我这边其实下过很 ...
- [转帖]Linux系统语言设置和locale命令详解
简介 Linux系统可以用locale命令查看语言设置,查看中英文环境,具体操作如下. 操作 1.查看当前安装有那些语言: [root@localhost /]# locale -a 2.当前语言相关 ...
- [转帖]如何优雅的使用 Systemd 管理服务
https://zhuanlan.zhihu.com/p/271071439 背景:我们在构建 Kubernetes 容器化平台时,会在节点上部署各种 agent ,虽然容器化当道的今天很多程序可以直 ...
- BPF的简单学习
BPF的简单学习 前言 本来规划过年期间学习一下bpf相关的内容 但是因为自己没有坚持学习,所以到最后一天才开始整理. 本来想深入学习一下相关内容,但是已经感觉已经无法完成. 最近大半年进行了很多性能 ...