比较简单的树形dp(递推?)
设$dp[i][j]$表示距离$i$距离为$j$的点的数目,先预处理$g[i][j]$表示点$i$的子树中距离这个点距离为$j$的点的数目(猫老师讲过,用一个栈维护一下就好了),然后再预处理根节点,之后开始考虑dp。
当进入一个儿子时,首先这个儿子对于所有距离$dis$会继承距离父亲$dis-1$的点,然后是它的子树中距离它为$dis$的点,但是这样距离它为$dis-2$的点会被算重复,减掉就好了
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100005,K=22; 6 int p[N],noww[2*N],goal[2*N]; 7 int num[N],stk[N],pts[N][K],dp[N][K]; 8 int n,k,t1,t2,cnt,top,ans; 9 void link(int f,int t) 10 { 11 noww[++cnt]=p[f]; 12 goal[cnt]=t,p[f]=cnt; 13 } 14 void MARK(int nde,int fth) 15 { 16 stk[++top]=nde; 17 for(int i=0;i<=k;i++) 18 if(top>i) pts[stk[top-i]][i]+=num[nde]; 19 for(int i=p[nde];i;i=noww[i]) 20 if(goal[i]!=fth) MARK(goal[i],nde); 21 top--; 22 } 23 void DFS(int nde,int fth) 24 { 25 dp[nde][0]=pts[nde][0]; 26 for(int i=1;i<=k;i++) 27 if(nde==1) dp[1][i]=pts[1][i]; 28 else dp[nde][i]=dp[fth][i-1]-pts[nde][i-2]+pts[nde][i]; 29 for(int i=p[nde];i;i=noww[i]) 30 if(goal[i]!=fth) DFS(goal[i],nde); 31 } 32 int main() 33 { 34 scanf("%d%d",&n,&k); 35 for(int i=1;i<n;i++) 36 { 37 scanf("%d%d",&t1,&t2); 38 link(t1,t2),link(t2,t1); 39 } 40 for(int i=1;i<=n;i++) 41 scanf("%d",&num[i]); 42 MARK(1,0); DFS(1,0); 43 for(int i=1;i<=n;i++) 44 { 45 ans=0; 46 for(int j=0;j<=k;j++) 47 ans+=dp[i][j]; 48 printf("%d ",ans); 49 } 50 return 0; 51 }