hdu 5647 DZY Loves Connecting 树形DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5647
题意:定义树节点子集的连通集为连通集中任意两个点均连通;连通集的大小即为连通集中点的个数;
树的总结点数不超过200000;求树的总的连通集的大小总和;孤立节点也为一个连通集,大小为1;
思路:树形DP。
ans为每个节点在多少个连通集中出现的sigma和;
dp[u][0]:以u为根节点的子树的连通集的个数;
dp[u][1]:以u为根节点的连通集的元素个数的总和;
所以当深搜到一个新的子节点v时,父节点u的连通集的元素总个数变为dp[u][1]*(dp[v][0]+1)+dp[v][1]*dp[u][0];
dp[u][1]*(dp[v][0]+1):父节点原来所有连通集中的点现在均可由于子节点连通集的加入而变成dp[v][0]倍。同时加上没加入子节点连通集时的本身;
dp[v][1]*dp[u][0]:这其实看的是父节点对子节点连通集中子节点的个数的增量;但是这也是以父节点为根情况;至于这里没有和上面一样+1,
是因为这样加一,ans += dp[v][1]中计算过了。同时从dp的含义也知道不能加了;
这里用到了相对的思想;可以看成是父节点的所有连通集加入到原理的子节点的连通集中,同样也可以反过来看。这样增加也是互增的;
#include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<vector> #include<cmath> #include<stdlib.h> #include<time.h> #include<stack> #include<set> #include<map> #include<queue> using namespace std; #define rep0(i,l,r) for(int i = (l);i < (r);i++) #define rep1(i,l,r) for(int i = (l);i <= (r);i++) #define rep_0(i,r,l) for(int i = (r);i > (l);i--) #define rep_1(i,r,l) for(int i = (r);i >= (l);i--) #define MS0(a) memset(a,0,sizeof(a)) #define MS1(a) memset(a,-1,sizeof(a)) #define MSi(a) memset(a,0x3f,sizeof(a)) #define inf 0x3f3f3f3f #define lson l, m, rt << 1 #define rson m+1, r, rt << 1|1 typedef pair<int,int> PII; #define A first #define B second #define MK make_pair typedef __int64 ll; template<typename T> void read1(T &m) { T x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} m = x*f; } template<typename T> void read2(T &a,T &b){read1(a);read1(b);} template<typename T> void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);} template<typename T> void out(T a) { if(a>9) out(a/10); putchar(a%10+'0'); } const int M = 200200; int head[M],tot; struct Edge{ int to,w,Next; Edge(){} Edge(int to,int w,int Next):to(to),w(w),Next(Next){} }e[M<<1]; inline void ins(int u,int v,int w) { e[++tot] = Edge{v,w,head[u]}; head[u] = tot; } const int mod = 1e9+7; ll dp[M][2]; void dfs(int u,int pre) { dp[u][0] = dp[u][1] = 1; for(int d = head[u];d;d = e[d].Next){ int v = e[d].to; if(v == pre) continue; dfs(v,u); dp[u][1] = (dp[u][1]*(dp[v][0] + 1)%mod + dp[v][1]*dp[u][0]%mod)%mod; dp[u][0] = dp[u][0]*(dp[v][0] + 1)%mod; //父节点连通集的变化 } } int main() { int n,T,u; read1(T); while(T--){ read1(n); //if(n == 1){puts("1");continue;} tot = 0;MS0(head);MS0(dp); rep1(i,2,n){ read1(u); ins(i,u,0);ins(u,i,0); } dfs(1,-1); ll ans = 0; rep1(i,1,n) ans = (ans+dp[i][1])%mod; out(ans); puts(""); } return 0; }