解题:USACO12FEB Nearby Cows

时间:2023-03-08 21:37:38

题面

比较简单的树形dp(递推?)

设$dp[i][j]$表示距离$i$距离为$j$的点的数目,先预处理$g[i][j]$表示点$i$的子树中距离这个点距离为$j$的点的数目(猫老师讲过,用一个栈维护一下就好了),然后再预处理根节点,之后开始考虑dp。

当进入一个儿子时,首先这个儿子对于所有距离$dis$会继承距离父亲$dis-1$的点,然后是它的子树中距离它为$dis$的点,但是这样距离它为$dis-2$的点会被算重复,减掉就好了

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,K=;
int p[N],noww[*N],goal[*N];
int num[N],stk[N],pts[N][K],dp[N][K];
int n,k,t1,t2,cnt,top,ans;
void link(int f,int t)
{
noww[++cnt]=p[f];
goal[cnt]=t,p[f]=cnt;
}
void MARK(int nde,int fth)
{
stk[++top]=nde;
for(int i=;i<=k;i++)
if(top>i) pts[stk[top-i]][i]+=num[nde];
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=fth) MARK(goal[i],nde);
top--;
}
void DFS(int nde,int fth)
{
dp[nde][]=pts[nde][];
for(int i=;i<=k;i++)
if(nde==) dp[][i]=pts[][i];
else dp[nde][i]=dp[fth][i-]-pts[nde][i-]+pts[nde][i];
for(int i=p[nde];i;i=noww[i])
if(goal[i]!=fth) DFS(goal[i],nde);
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=;i<n;i++)
{
scanf("%d%d",&t1,&t2);
link(t1,t2),link(t2,t1);
}
for(int i=;i<=n;i++)
scanf("%d",&num[i]);
MARK(,); DFS(,);
for(int i=;i<=n;i++)
{
ans=;
for(int j=;j<=k;j++)
ans+=dp[i][j];
printf("%d\n",ans);
}
return ;
}