题意:
给一棵树,求这棵树的所有连通子图的点的数量之和?( n≤105 )
解释:
dfs+dp 很好的题!
dp[u] 表示以 u 为根节点的不同的子树的数量,S[u] 表示 以 u 为根节点的所有不同子树的节点的数量之和
那么对于叶子节点:dp[u]=S[u]=1
转移:( v 为u 的儿子节点)
S[u]=(1+dp[v])∗S[u]+dp[u]∗S[v]
dp[u]=dp[u]∗(1+dp[v])
(注意取模MOD)
怎么理解这个转移方程呢?利用第一个样例理解下就行了,还是比较好理解的!
PS: 妈的,还差 5min 就 AK 了
代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <string>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> P;
const int N = 5 + 1e5,MOD = 7+1e9;
vector<int> G[N];
int a[N];
LL dp[N], S[N];
void getTree(int n, int a0, int b, int c, int m)
{
a[0] = a0;
for(int i = 1;i <= n - 2;i ++) a[i] = int((1LL * b * a[i-1] + 1LL * c) % m);
for(int i = 1;i <= n - 1;i ++) {
int j = a[i - 1] % i;
G[i].PB(j), G[j].PB(i);
}
}
void dfs(int u, int fa)
{
for(int i = 0;i < G[u].size();i ++) {
int v = G[u][i];
if(v == fa) continue;
dfs(v, u);
if(dp[u] == 0) dp[u] = (1 + dp[v]) % MOD, S[u] = (S[v] + dp[v] + 1) % MOD;
else S[u] = ((1 + dp[v]) * S[u] % MOD + (dp[u] * S[v] % MOD)) % MOD, dp[u] = dp[u] * (1 + dp[v]) % MOD;
}
}
class SubtreesCounting {
public:
int sumOfSizes(int n, int a0, int b, int c, int m) {
for(int i = 0;i < n;i ++) G[i].clear();
getTree(n, a0, b, c, m);
for(int i = 0;i < n;i ++) dp[i] = S[i] = 1LL;
dfs(0, -1);
LL ans = 0;
for(int i = 0;i < n;i ++) ans = (ans + S[i]) % MOD;
return ans;
}
};