【HDU5647 BestCoder Round 76 (div1)B】【树形DP】DZY Loves Connecting 一棵树的所有生成子树的大小乘积
来源:互联网 发布:淘宝逆战代刷 编辑:程序博客网 时间:2024/05/01 01:56
DZY Loves Connecting
Accepts: 16
Submissions: 169
Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 262144/262144 K (Java/Others)
问题描述
DZY有一棵n个结点的无根树,结点按照1∼n标号。DZY喜欢树上的连通集。一个连通集S是由一些结点组成的集合,满足S中任意两个结点u,v能够用树上的路径连通,且路径上不经过S之外的结点。显然,单独一个结点的集合也是连通集。一个连通集的大小定义为它包含的结点个数,DZY想知道所有连通集的大小之和是多少。你能帮他数一数吗?答案可能很大,请对109+7取模后输出。
输入描述
第一行t,表示有t组数据。接下来t组数据。每组数据第1行一个数n。第2∼n行中,第i行包含一个数pi,表示i与pi有边相连。(1≤pi≤i−1,2≤i≤n)(n≥1,所有数据中的n之和不超过200000)
输出描述
每组数据输出一行答案,对109+7取模。
输入样例
2151223
输出样例
142
Hint
第二个样例中,树的4条边分别为(1,2),(2,3),(2,4),(3,5)。所有连通集分别是{1},{2},{3},{4},{5},{1,2},{2,3},{2,4},{3,5},{1,2,3},{1,2,4},{2,3,4},{2,3,5},{1,2,3,4},{1,2,3,5},{2,3,4,5},{1,2,3,4,5}。
If you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<ctype.h>#include<math.h>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(x))#define MP(x,y) make_pair(x,y)#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }const int N = 2e5+10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;int casenum, casei;LL sum[N];//sum[i]表示以i为根节点的所有可能的子树大小之和LL num[N];//num[i]表示以i为根节点的子树方案int n, x;vector<int>a[N];LL ans;void dfs(int x,int fa){num[x] = 1;sum[x] = 1;for (int i = a[x].size() - 1; ~i; --i){int y = a[x][i];if (y == fa)continue;dfs(y, x);sum[x] = (sum[x] * (num[y] + 1) + sum[y] * num[x]) % Z;num[x] = num[x] * (num[y] + 1) % Z;}ans = (ans + sum[x]) % Z;}int main(){scanf("%d", &casenum);for (casei = 1; casei <= casenum; ++casei){scanf("%d", &n);for (int i = 1; i <= n; ++i)a[i].clear();for (int i = 2; i <= n; ++i){scanf("%d", &x);a[i].push_back(x);a[x].push_back(i);}ans = 0;dfs(1, 0);printf("%lld\n", ans);}return 0;}/*【trick&&吐槽】1,BC会爆栈BC会爆栈BC会爆栈BC会爆栈BC会爆栈BC会爆栈BC会爆栈2,不论是用费马小定理求逆元还是拓展欧几里得求逆元,都要注意要使得gcd()==1这里不光要要求模数Z为素数。因为只是涉及到乘法还无所谓,很多时候还涉及到加法,这就可能会使得方案数为Z的倍数。于是我们要尽量避免求逆元运算。3,留时间制造hack数据>_<,比如爆栈啦,比如子树的形态构建啦【题意】一棵树n(2e5)个节点,问所有子树size的乘积。【类型】树形DP【分析】首先因为是棵树,所以不妨以1为父节点。然后我们发现,总归要有一个节点为整棵子树的根节点的。于是,我们枚举一个点为子树的根节点,然后求其为子树根节点时的子树的大小之和以及子树个数定义:LL sum[N];//sum[i]表示以i为根节点的所有可能的子树大小之和LL num[N];//num[i]表示以i为根节点的子树方案显然答案就是∑sum[]。然而这个DP要怎么展开呢?void dfs(int x,int fa){num[x] = 1;//只算x作为根节点时的自己,方案数为1sum[x] = 1;//只算x作为根节点时的自己,子树大小和为1for (int i = a[x].size() - 1; ~i; --i){int y = a[x][i];if (y == fa)continue;dfs(y, x);//之前子树的大小会变成*(num[y]+1)种可行方案//新的子树(y)大小会变成sum[y]*num[x]种可行方案sum[x] = (sum[x] * (num[y] + 1) + sum[y] * num[x]) % Z;//子树方案会变成*(num[y]+1)种num[x] = num[x] * (num[y] + 1) % Z;}ans = (ans + sum[x]) % Z;}【时间复杂度&&优化】O(n)*/
0 0
- 【HDU5647 BestCoder Round 76 (div1)B】【树形DP】DZY Loves Connecting 一棵树的所有生成子树的大小乘积
- hdu5647 DZY Loves Connecting (树形dp)
- 树型dp hdu5647 DZY Loves Connecting
- 【HDU5647】DZY Loves Connecting【TreeDP】
- 【HDU5648 BestCoder Round 76 (div1)C】【打表or数位DP】DZY Loves Math nm范围内i和j i或j的gcd之和
- 【HDU5646 BestCoder Round 76 (div1)A】【贪心】DZY Loves Partition n个数拆分k个最大乘积
- BC#76 C_HDU5647 DZY Loves Connecting 树形DP
- HDU 5647 - DZY Loves Connecting (树形dp)
- hdu 5647 DZY Loves Connecting (树形dp)
- HDU-5647 DZY Loves Connecting(树形dp)
- 【HDU5649 BestCoder Round 76 (div1)D】【二分+线段树】DZY Loves Sorting 全排列1~n 区间升序降序排序 最后k位置的数是几
- HDU-5647 DZY Loves Connecting(树形dp)
- 【HDU5569 BestCoder Round 63 (div1)B】【DP】matrix 向右走向下走最大乘积和
- BestCoder Round #35(DZY Loves Balls-暴力dp)
- BestCoder Round #76 (div.2) DZY Loves Balls
- BestCoder Round #76 (div.2)-DZY Loves Partition(模拟)
- 【BestCoder Round #76 (div.2)】DZY Loves Partition(数学分析)
- 【HDU5653 BestCoder Round 77 (div1) C】【DP 复杂度计算】Bomber Man wants to bomb an Array n炸弹设置爆炸左右界 最大爆炸力的乘积
- 天声人語 20160320 シジュウカラがつづる「文」
- Oracle 11g 新特性 -- Database Replay (重演)
- 谷歌浏览器 标签
- POJ1833 排列
- java数据结构排序之堆排序算法实现
- 【HDU5647 BestCoder Round 76 (div1)B】【树形DP】DZY Loves Connecting 一棵树的所有生成子树的大小乘积
- 连续发送多份小数据时40ms延迟问题
- 一道笔试题 - 数字转大写金额
- 日经春秋 20160320
- 神经网络模型算法与生物神经网络的最新联系
- ProgressDialog的dismiss方法与cancel方法的区别
- BC#76.2DZY Loves Balls
- javascript——MD5加密脚本
- datawindowchild的GetSQLSelect()方法获取 sql