题面:https://ac.nowcoder.com/acm/contest/35232/D
解题思路:
先分层,然后每层的深度去乘到这层的概率P。
听上去挺简单的,只要算出概率P就行.
这个概率P就是这一层以上的所有点都没被感染的概率,乘以这一层至少有一个被感染概率。
但是这题狗就狗在,不仅有初始的感染概率,还有之后点与点之间的感染概率。(注意这里向下传染是不会改变等级的,所以研究向上传染的问题就行)
所以这个概率P细分:
- 这一层以上初始时所有点没被感染的概率—从第一层开始递推,直接累乘(1-pi)就行。
- 这一层至少有一个被感染的概率(包括初始的和后来被感染的),这里要对每一个点进行计算,算出他被感染的概率ppi,那么这一层被感染的概率就是1-(1-pp1)(1-pp2)……
- 对于ppi,它有两个部分,一个部分是初始就被感染,还有一个部分是初始没被感染但是儿子被感染且传给它了(这里是加号)。注意这里儿子被感染,是包括初始和之后被感染的,所以很显然这部分也要用递推,从最底层往上递推。
- 你以为这就完了?其实仔细看第一个是初始时没被感染,还有一个是不被这一层感染的点所感染的概率啊,这个需要再计算完第二步之后,对每个点再算。
这几个递推哪个可以写在dfs里,哪个写在外面,主要就是看是按点算还是按层算。
#include<bits/stdc++.h>
#define DEBUG(x) cout<<"** "<<x<<" **"<<endl;
using namespace std;
typedef long long ll;
#define N 200005
const ll mod=1e9+7;
struct node{
int num;
ll p;
node(int x,ll y){
num=x;
p=y;
}
};
ll fpm(ll x){
x%=mod;
ll res=1;
ll mm=mod-2;
while(mm){
if(mm&1)res*=x,res%=mod;
x*=x;
x%=mod;
mm>>=1;
}
return res;
}
ll dp[N],init[N],pre[N],tofa[N];
//总的被感染的概率;初始;这一层之前全不被感染;传染给父亲的概率。
int dep[N],fa[N];
vector<node> g[N];
vector<int> la[N];//每一层的深度
int mx=0;
ll ans=0;
void dfs(int root,int f){
dep[root]=dep[f]+1;
fa[root]=f;
mx=max(dep[root],mx);
la[dep[root]].push_back(root);
if(g[root].size()==1&&root!=1){
dp[root]=init[root];
return ;
}
ll tmp=1;
for(int i=0;i<g[root].size();i++){
int s=g[root][i].num;
int t=g[root][i].p;
if(s==f)continue;
tofa[s]=t;
dfs(s,root);
tmp=(tmp*(1+mod-dp[s]*t%mod))%mod;
}
dp[root]=((1+mod-tmp)*(1+mod-init[root])%mod+init[root])%mod;
}
void add(int i){
ll thistmp=1;
ll uptmp=1;
for(int j=0;j<la[i].size();j++){
int s=la[i][j];
thistmp=(thistmp*(1-dp[s]+mod))%mod;
uptmp=(uptmp*(1+mod-dp[s]*tofa[s]%mod))%mod;
}
ans=(ans+pre[i-1]*(1-thistmp-(1-uptmp)+mod)%mod*i)%mod;
}
int main(){
int n;
cin>>n;
ll x,y;
for(int i=1;i<=n;i++){
scanf("%lld %lld",&x,&y);
y=fpm(y);
init[i]=(x*y)%mod;
}
int px,py;
for(int i=1;i<n;i++){
scanf("%d %d %lld %lld",&px,&py,&x,&y);
y=fpm(y);
x=(x*y)%mod;
g[px].push_back(node(py,x));
g[py].push_back(node(px,x));
}
if(n==1){
cout<<init[1]<<endl;
return 0;
}
dep[0]=0;
dfs(1,0);
pre[0]=1;
for(int i=1;i<=mx;i++){
pre[i]=pre[i-1];
for(int j=0;j<la[i].size();j++){
int s=la[i][j];
pre[i]=(pre[i]*(1+mod-init[s]))%mod;
}
}
// for(int i=1;i<=n;i++){
// DEBUG(pre[i]);
// }
for(int i=mx;i;i--){
add(i);
}
cout<<ans<<endl;
return 0;
}