luogu5007 DDOSvoid 的疑惑 (树形dp)

我们来算每个点出现在的集合的个数

设f[i]为i出现的集合个数,g[i]是只选子树i 可以有多少种选法

那就有$g[i]=1+\prod\limits_{j是i的孩子}{g[j]} , f[i]=f[fa[i]]*\prod\limits_{j是i的兄弟}{f[j]}$

这个兄弟的积可以直接用一个逆元 或者是做前缀积和后缀积然后乘起来,但千万不要一边记着后缀积一边又进子树dfs 你孩子全都给你改没了(摔

那我们肯定能不带log就不带嘛

 1 #include<bits/stdc++.h>
 2 #define CLR(a,x) memset(a,x,sizeof(a))
 3 using namespace std;
 4 typedef long long ll;
 5 typedef pair<int,int> pa;
 6 const int maxn=1e6+10,P=1e8+7;
 7 
 8 inline ll rd(){
 9     ll x=0;char c=getchar();int neg=1;
10     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
12     return x*neg;
13 }
14 
15 int eg[maxn*2][2],egh[maxn],ect;
16 int N,T,stk[maxn];
17 ll choi[maxn],dp[maxn];
18 ll pre[maxn],ans;
19 
20 inline void adeg(int a,int b){
21     eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect;
22 }
23 
24 void dfs1(int x,int f){
25     choi[x]=1;
26     for(int i=egh[x];i;i=eg[i][1]){
27         int b=eg[i][0];if(b==f) continue;
28         dfs1(b,x);
29         choi[x]=choi[x]*choi[b]%P;
30     }
31     choi[x]++;choi[x]%=P;
32 }
33 
34 void dfs2(int x,int f){
35     ans+=dp[x]*(T?x:1)%P,ans%=P;
36     int n=0;
37     for(int i=egh[x];i;i=eg[i][1]){
38         int b=eg[i][0];if(b==f) continue;
39         stk[++n]=b;
40     }
41     pre[n+1]=1;
42     for(;n;n--) pre[n]=pre[n+1]*choi[stk[n]]%P;
43     ll a=dp[x];
44     for(int i=egh[x];i;i=eg[i][1]){
45         int b=eg[i][0];if(b==f) continue;
46         ++n;dp[b]=a*pre[n+1]%P;
47         a*=choi[b],a%=P;
48     }
49     for(int i=egh[x];i;i=eg[i][1]){
50         int b=eg[i][0];
51         if(b==f) continue;
52         dfs2(b,x);
53     }
54 }
55 
56 int main(){
57     //freopen("","r",stdin);
58     int i,j,k;
59     N=rd(),T=rd();
60     for(i=1;i<N;i++){
61         int a=rd(),b=rd();
62         adeg(a,b);adeg(b,a);
63     } 
64     dfs1(1,0);dp[1]=1;dfs2(1,0);
65     printf("%lld\n",(ans+P)%P);
66     return 0;
67 }

 

posted @ 2018-11-05 22:00  Ressed  阅读(162)  评论(0编辑  收藏  举报