显然的,假如把每队 \((u_i,v_i)\) 都连一条 \(u_i\to v_i\) 的边,那么一定会形成一棵树,但有外向边也有内向边,其中外向边的定义是从近 \(1\) 点连向远 \(1\) 点的边,内向边相反。
先考虑只有外向边的情况。显然 \(1\) 号必须最后抽,概率为 \(\frac{w_1}{\sum\limits_{i=1}^nw_i}\),然后问题就分解到了他的所有儿子的子树里。一看就有满满的 \(dp\) 味道。设 \(f_{x,i}\) 表示在 \(x\) 子树中,\(\sum\limits_{y\in subtree(x)}w_y=i\) 且满足要求的可能情况数,转移时间复杂度 \(O(n^2)\)。
假如遇到反向边,根据容斥原理,答案 \(=\) 这里没边 \(-\) 这里是正向边,也不难处理。
时间复杂度 \(O(n^2)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1005,p=998244353;
struct edge{int to,w;};
int n,inv[N*3],f[N][N*3],b[3][N];
vector<edge>g[N];int a[N*3],sz[N];
int qpow(int x,int y){int re=1;while(y){if(y&1) re=re*x%p;x=x*x%p,y>>=1;}return re;
}void dfs(int x,int fa){f[x][0]=1;for(auto cc:g[x]) if(cc.to!=fa){dfs(cc.to,x);int y=cc.to,sm=0;int w=cc.w,sx=sz[x]*3,sy=sz[y]*3;for(int i=0;i<=sx+sy;i++) a[i]=0;if(!w) for(int i=0;i<=sx;i++)for(int j=0;j<=sy;j++) a[i+j]=(a[i+j]+f[x][i]*f[y][j])%p;else{for(int i=0;i<=sy;i++) sm=(sm+f[y][i])%p;for(int i=0;i<=sx;i++) a[i]=sm*f[x][i]%p;for(int i=0;i<=sx;i++) for(int j=0;j<=sy;j++)a[i+j]=(a[i+j]-f[x][i]*f[y][j]%p+p)%p;}for(int i=0;i<=sx+sy;i++) f[x][i]=a[i];sz[x]+=sz[y];}int sx=(sz[x]++)*3;for(int i=0;i<=sx+3;i++) a[i]=0;for(int i=0;i<=sx;i++){a[i+1]=(a[i+1]+f[x][i]*b[0][x]%p*inv[i+1])%p;a[i+2]=(a[i+2]+f[x][i]*b[1][x]%p*inv[i+2]*2)%p;a[i+3]=(a[i+3]+f[x][i]*b[2][x]%p*inv[i+3]*3)%p;}for(int i=0;i<=sx+3;i++) f[x][i]=a[i];
}signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);inv[0]=inv[1]=1,cin>>n;for(int i=2;i<=n*3;i++)inv[i]=(p-p/i)*inv[p%i]%p;for(int i=1,cc;i<=n;i++){cin>>b[0][i]>>b[1][i]>>b[2][i];cc=qpow(b[0][i]+b[1][i]+b[2][i],p-2);for(int j=0;j<3;j++) b[j][i]=b[j][i]*cc%p;}for(int i=1,x,y;i<n;i++)cin>>x>>y,g[x].push_back({y,0}),g[y].push_back({x,1});dfs(1,0);int ans=0;for(int i=sz[1]*3;~i;i--) ans+=f[1][i];return cout<<ans%p,0;
}