传送门:点击打开链接
题意:定义连通集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; }