树型dp hdu5647 DZY Loves Connecting

传送门:点击打开链接

题意:定义连通集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;
}



你可能感兴趣的:(树型dp hdu5647 DZY Loves Connecting)