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 ...
随机推荐
- Postman调试grpc
转载请注明出处: 1.检查自己的postman是否支持 grpc,通过 File -> new -> ,出现如下图,则表示支持: 2.点击上图的grpc就会自动创建一个 grpc 的req ...
- Django应用中的静态文件处理
在日常开发中,我们都是把Django的Debug模式打开,方便调试,在这个模式下,由Django内置的Web服务器提供静态文件服务,不过需要进行一些配置,才能正确访问. 配置settings # St ...
- [转帖]GC 日志
https://www.xjx100.cn/news/188814.html?action=onClick 垃圾回收器的发展历史 1999年:随JDK1.3.1一起来的串行方式Serial GC(第一 ...
- [转帖]A17再次证明苹果才是王者,组装芯片的安卓手机给它提鞋都不配
http://news.sohu.com/a/653472711_121124371 在挤了两代牙膏之后,苹果终于拿出了性能大幅提升的A17处理器,外媒传出A17处理器的性能提升幅度至少超过四成,相比 ...
- [转帖]查看堆内对象的工具:jmap
文章目录 用途 命令格式 示例 一,no option 二,heap 三,histo[:live] 四,clstats 五,finalizerinfo 六,dump:<dump-options& ...
- 使用smem 计算Oracle用户下内存占用情况.
1. 本来计划使用 ps 命令进行查看, 但是发现ps 最多查询出来的是 RSS的内存数据, 会多添加很多冗余的内存数据量进来, 于是作罢 2. 找了下公司的方神, 说可以使用smem 然后简单看了下 ...
- StorageClass 简单学习
StorageClass 简单学习 学习资料来源 https://www.jianshu.com/p/5e565a8049fc https://zhuanlan.zhihu.com/p/2895019 ...
- ZCube:在我的优惠券中的落地实践 | 京东云技术团队
前言 我的优惠券作为营销玩法的一种运营工具,在营销活跃场中起到很至关重要的作用.如何更加高效的赋能业务,助理业务发展,灵活扩展业务,是我们一直追求和思考的方向 一.背景 1.1 现状 营销中台作为 ...
- 买彩票能中大奖?用Java盘点常见的概率悖论 | 京东云技术团队
引言 <双色球头奖概率与被雷劈中的概率哪个高?> <3人轮流射击,枪法最差的反而更容易活下来?> 让我们用Java来探索ta们! 悖论1:著名的三门问题 规则描述:你正在参加一 ...
- vue/cli中css.sourceMap-open-inline-host-port-https-openPage-compress -devServer.proxy的简单介绍
Vue/cli4.0 配置属性--css.sourceMap 设置是否开启 css 的 sourse map功能. css 的 sourse map作用类似与 js 的 sourse map. 注意: ...