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 }