树形DP,设f[i][j]是当前在i点,j步之内有多少牛。从相邻点to的f[to][j-1]转移而来,减去重复计算即可。
#include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<cstdlib> #define maxn 150020 #define maxk 22 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch==‘-‘) f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-‘0‘; ch=getchar(); } return num*f; } struct Edge{ int next,to; }edge[maxn*2]; int head[maxn],num; inline void add(int from,int to){ edge[++num]=(Edge){head[from],to}; head[from]=num; } long long f[maxn][maxk]; long long d[maxn]; int main(){ int n=read(),m=read(); for(int i=1;i<n;++i){ int x=read(),y=read(); add(x,y); add(y,x); d[x]++; d[y]++; } for(int i=1;i<=n;++i) f[i][0]=read(); for(int i=1;i<=n;++i){ f[i][1]+=f[i][0]; for(int j=head[i];j;j=edge[j].next){ int to=edge[j].to; f[i][1]+=f[to][0]; } } for(int j=2;j<=m;++j) for(int i=1;i<=n;++i){ for(int k=head[i];k;k=edge[k].next){ int to=edge[k].to; f[i][j]+=f[to][j-1]; } f[i][j]-=f[i][j-2]*(d[i]-1); } for(int i=1;i<=n;++i) printf("%lld\n",f[i][m]); return 0; }