HDU-5647 DZY Loves Connecting(树形dp)

DZY Loves Connecting

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 500    Accepted Submission(s): 171


Problem Description
DZY has an unrooted tree consisting of  n  nodes labeled from  1  to  n .

DZY likes connected sets on the tree. A connected set  S  is a set of nodes, such that every two nodes  u,v  in  S  can be connected by a path on the tree, and the path should only contain nodes from  S . Obviously, a set consisting of a single node is also considered a connected set.

The size of a connected set is defined by the number of nodes which it contains. DZY wants to know the sum of the sizes of all the connected sets. Can you help him count it?

The answer may be large. Please output modulo  109+7 .
 

Input
First line contains  t  denoting the number of testcases.
t  testcases follow. In each testcase, first line contains  n . In lines  2n i th line contains  pi , meaning there is an edge between node  i  and node  pi . ( 1pii1,2in )

( n1 , sum of  n  in all testcases does not exceed  200000 )
 

Output
Output one line for each testcase, modulo  109+7 .
 

Sample Input
   
   
   
   
2 1 5 1 2 2 3
 

Sample Output
   
   
   
   
1 42
Hint
In the second sample, the 4 edges are (1,2),(2,3),(2,4),(3,5). All the connected sets are {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++.
 

Source
BestCoder Round #76 (div.2) 
 
迟到一周的题解,偷懒了好几天……

题意:

给你一系列的点和边,构成一棵无根树。要求计算出图中所有连通块大小之和,连通块的大小即是连通块包含多少元素。

分析:

最近恰好在练习树形dp,当时看到这题跃跃欲试,结果还是滚粗。

看官方的题解也云里雾里,只理解了把含结点n的连通块数量全部相加最后就可以得到大小之和,最后还是第二天看了题解才明白正确做法。

用f[i]表示包含i的连通块数量,g[i]表示以i为根节点的连通块的数量。

下面给出DP方程:

f[n]=f[n]*(g[son[n][i]]+1)%mod+g[n]*f[son[n][i]]%mod;

f[n]%=mod;

g[n]=g[n]*(g[son[n][i]]+1)%mod;

f[n]*(g[son[n][i]]+1):对于结点包含n的连通块数量f[n],当检测到新子结点时,自身大小要乘上以子结点为根的连通块数量,同时还要加上自身

g[n]*f[son[n][i]]:子结点的连通块同样需要更新

g[n]=g[n]*(g[son[n][i]]+1):此处是对以n为根节点的连通块数量进行更新,每多一个子结点,之前的结果都要对该子树进行更新。

最后处理一下就好了,看题解的时候发现有些和自己之前码的几乎一致,细节处理不好就是做不出来。。。

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const int N=200005;
const int mod=1e9+7;

vector<int> son[N];
long long g[N],f[N];

void dfs(int n,int fa){
    for (int i=0; i<son[n].size(); i++) {
        if (son[n][i]==fa) {
            continue;
        }
        dfs(son[n][i],n);
        f[n]=f[n]*(g[son[n][i]]+1)%mod+g[n]*f[son[n][i]]%mod;
        f[n]%=mod;
        g[n]=g[n]*(g[son[n][i]]+1)%mod;
    }
}


int main() {
    int t,n;
    cin>>t;
    while (t--) {
        int temp;
        cin>>n;
        for (int i=0; i<=n; i++) {
            son[i].clear();
            g[i]=f[i]=1;
        }
        for (int i=2; i<=n; i++) {
            scanf("%d",&temp);
            son[temp].push_back(i);
            son[i].push_back(temp);
        }
        long long sum=0;
        dfs(1,-1);
        for (int i=1; i<=n; i++) {
            sum+=f[i];
            sum%=mod;
        }
        cout<<sum<<endl;
    }
    return 0;
}


你可能感兴趣的:(HDU-5647 DZY Loves Connecting(树形dp))