【树形DP】【2014-3】day5 T2 暴力


最近被狂虐。。。

题解没看懂,自己乱想了个DP,发现和标程的方法一模一样

然后发现自己完全不会写递推,只看懂了dfs1,dfs2尤其是q[]简直完全没懂

以前总以为这类DP很简单直到今天。。。。。。。。。。。。。。


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define rep(i,l,r) for(int i=(l),_=(r);i<=_;i++)
#define per(i,r,l) for(int i=(r),_=(l);i>=_;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define INE(i,u) for(int i=head[u];~i;i=e[i].next)
#define LL long long
inline const int read()
{int r=0,k=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}

const int N=100010;
const LL mod=1000000007;
int n;
struct edge{int v,next;}e[N*2];
int head[N],k;
LL a[N],b[N];
LL f[N],g[N],p[N],q[N],inv[N];

inline void MOD(LL &x){if(x>=mod)x-=mod;else if(x<0)x+=mod;}
inline void adde(int u,int v){e[k]=(edge){v,head[u]};head[u]=k++;}
inline LL pow_mod(LL a,LL b,LL p){LL t=1;for(;b;b>>=1,a=a*a%p)if(b&1)t=t*a%p;return t;}
void dfs1(int u,int fa)
{
	f[u]=1; g[u]=0;
	INE(i,u)
	{
		int v=e[i].v; if(v==fa) continue;
		dfs1(v,u);
		f[u]=f[u]*(f[v]+1)%mod;
	}
	inv[u]=pow_mod(f[u]+1,mod-2,mod);
	INE(i,u)
	{
		int v=e[i].v; if(v==fa) continue;
		g[u]=g[u] + f[u] * inv[v] % mod * g[v] % mod; MOD(g[u]);
	}
	g[u]+=f[u]*b[u]%mod; MOD(g[u]);
	//printf("f[%d]=%I64d g[%d]=%I64d\n",u,f[u],u,g[u]);
}
void dfs2(int u,int fa)
{
	INE(i,u)
	{
		int v=e[i].v; if(v==fa) continue;
		p[v]=(p[u] * inv[v] + 1) % mod * f[v] % mod; MOD(p[v]);
		int tmp = p[u] * inv[v] % mod;
	    q[v] = (g[v] * (tmp + 1) % mod + (q[u] - tmp * g[v] % mod + mod) % mod * inv[v] % mod * f[v] % mod) % mod; MOD(q[v]);
		//printf("p[%d]=%I64d q[%d]=%I64d\n",v,p[v],v,q[v]);
	    dfs2(v,u);
	}
}

void input()
{
	MS(head,-1);
    n=read();
    rep(i,1,n-1)
    {
    	int u=read(),v=read();
    	adde(u,v); adde(v,u);
    }
    rep(i,1,n) a[i]=read();
    rep(i,1,n) b[i]=read();
}
void solve()
{
	dfs1(1,-1);
	p[1]=f[1]; q[1]=g[1];
	dfs2(1,-1);
	LL ans=0;
	rep(i,1,n) MOD(ans+=q[i]*a[i]%mod);
	cout<<ans<<endl;
}

int main()
{
    freopen("c.in","r",stdin); freopen("c.out","w",stdout);
    input(),solve();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值