zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    [转] STM32 FSMC学习笔记
    【转】嵌入式系统 Boot Loader 技术内幕
    mini2440 使用 JLink V8 直接烧写 Nor flash
    S3C6410移植uboot(一)
    2440的RTC时钟
    关闭2440 屏幕背光
    基于十级流水线的开立方根算法
    Visual Studio 2008配置SystemC开发环境
    Linux C 中字符串化操作符#
    linux 中 timeval结构体
  • 原文地址:https://www.cnblogs.com/hxer/p/5314542.html
Copyright © 2011-2022 走看看