传送门:点击打开链接
题意:定义连通集S为,任意一对u,v属于S,u到v的树最短路径经过所有的节点都在S内。求所有这样的连通集大小之和
思路:看到维护大小之和,通常还需要维护数量。
看了下吉司机的代码写的很简单,只要理解好乘法原理,就很好做了
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <Stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout << "[" << x << "]"
#define FIN freopen("input.txt", "r", stdin)
#define FOUT freopen("output.txt", "w+", stdout)
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MX = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
struct Edge {
int v, nxt;
} E[MX << 1];
int Head[MX], erear;
void edge_init() {
erear = 0;
memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v) {
E[erear].v = v;
E[erear].nxt = Head[u];
Head[u] = erear++;
}
LL A[MX], B[MX];
void DFS(int u, int f) {
A[u] = B[u] = 1;
for(int i = Head[u]; ~i; i = E[i].nxt) {
int v = E[i].v; if(v == f) continue;
DFS(v, u);
B[u] = (B[u] * (A[v] + 1) + A[u] * B[v]) % mod;
A[u] = A[u] * (A[v] + 1) % mod;
}
}
int main() {
int T, n; //FIN;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
edge_init();
for(int u = 2; u <= n; u++) {
int v; scanf("%d", &v);
edge_add(u, v);
edge_add(v, u);
}
DFS(1, -1);
LL ans = 0;
for(int i = 1; i <= n; i++) {
ans = (ans + B[i]) % mod;
}
printf("%I64d\n", ans);
}
return 0;
}