码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round #302 (Div. 1 D)

时间:2015-05-10 09:47:50      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:dp   树形dp   

http://codeforces.ru/contest/543/problem/D

Problem

给一棵树,n个节点,n-1条边。把每个点当作首都,输出一个结果,一共要输出n个结果。边有两种形态,一种是好边,一种是坏边,当把一个点当作首都的时候,要求这个点到每个点的路径上坏边总数<=1,问有多少种树的形态。

n: 10^5级别

Solution

很显然树形dp。设dp[i]表示,以 i 为根的子树的方案数。如果只需要算dp[1],直接dfs一遍,回溯的时候,dp[i]=(dp[j]+1),其中 j是 i 的儿子。

那么,要算每个点的dp值怎么办呢?通过第一次dfs,我可以算出每个点的dp[i],表示以 i 为根的子树的方案数,然后再dfs一遍,算出以 i 为中心的方案数即可。脑补下dp方程就出来了,不写了。注意下,不能用逆元,费马小定理 ap?11(mod p),当gcd(a,p)1的时候,不成立,也就是a=0的时候会出事。想办法不用逆元,改用一个前缀积、后缀积就好了。

//Hello. I‘m Peter.
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define MAXN
#define N 200100
#define M
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
const int mod=1e9+7;
int n;
struct Edge{
    int from,to,next;
}edge[N<<1];
int head[N],num_edge;
inline void add_Edge(int from,int to){
    int t=++num_edge;
    edge[t].from=from;
    edge[t].to=to;
    edge[t].next=head[from];
    head[from]=t;
}
ll dp[N],pre[N],suf[N],ans[N];
inline void dfs(int now,int comfrom){
    dp[now]=1;
    for(int i=head[now];i!=-1;i=edge[i].next){
        int to=edge[i].to;
        if(to==comfrom) continue;
        dfs(to,now);
        dp[now]=dp[now]*(dp[to]+1)%mod;
    }
}
int fa[N];
inline void bfs(){
    queue<int>q;
    q.push(1);
    fa[1]=0;
    ans[1]=dp[1];
    dp[1]=0;
    vector<int>son;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        son.clear();
        for(int i=head[now];i!=-1;i=edge[i].next){
            int to=edge[i].to;
            if(fa[now]==to) continue;
            fa[to]=now;
            son.push_back(to);
        }
        int len=(int)son.size();
        ll nowv=1;
        for(int i=0;i<len;i++){
            pre[i]=nowv;
            nowv=nowv*(dp[son[i]]+1)%mod;
        }
        nowv=1;
        for(int i=len-1;i>=0;i--){
            suf[i]=nowv;
            nowv=nowv*(dp[son[i]]+1)%mod;
        }
        int t=0;
        for(int i=head[now];i!=-1;i=edge[i].next){
            int to=edge[i].to;
            if(fa[now]==to) continue;
            ll nowv=pre[t]*suf[t]%mod;
            nowv=nowv*(dp[now]+1)%mod;
            ans[to]=dp[to]*(nowv+1)%mod;
            q.push(to);
            t++;
            dp[to]=nowv;
        }
    }
}
int main(){
    n=read();
    num_edge=0;
    for(int i=1;i<=n;i++){
        head[i]=-1;
    }
    for(int i=2;i<=n;i++){
        int p=read();
        add_Edge(p,i);
        add_Edge(i,p);
    }
    dfs(1,0);
    bfs();
    for(int i=1;i<=n;i++){
        if(i!=1) printf(" ");
        printf("%d",(int)ans[i]);
    }
    printf("\n");
    return 0;
}

Codeforces Round #302 (Div. 1 D)

标签:dp   树形dp   

原文地址:http://blog.csdn.net/uestc_peterpan/article/details/45606475

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!