[USACO12FEB]附近的牛Nearby Cows

题目链接:QAQ

题目大意:给出一棵n个点的树,每个点上有\(C_i\)头牛,问每个点k步范围内各有多少头牛。

Solution:

首先看看数据范围,\(n\le1e5,k\le20\),那我们可以尝试设\(f[n][k]\)

\(d[i][j]\)表示从i点开始向下k的范围内有多少头牛,\(f[i][j]\)代表从i点开始j范围内有多少头牛

\(d[i][j]\)可以很容易算出来,对于一个点\(u\),\(d[u][j]=C_u+\sum_{v\in son_u}d[v][j-1]\)

\(f[i][j]\)也可以得出,\(f[v][j]=f[fa[v]][j-1]-d[v][j-2]+d[v][j]\)

最后输出\(f[i][k]\)就行了

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1;
int n,k,cnt,head[N];
int a[N],d[N][21],f[N][21];
struct Edge{int nxt,to;}edge[N<<1];
void ins(int x,int y){
	edge[++cnt].nxt=head[x];
	edge[cnt].to=y;head[x]=cnt;
}
void dfs(int x,int fa,int u){
	d[x][u]+=a[x];
	for(int i=head[x];i;i=edge[i].nxt){
		int y=edge[i].to;
		if(y==fa) continue;
		d[x][u]+=d[y][u-1];
		dfs(y,x,u);
	}
}
void calc(int x,int fa,int u){
	int w=u-2>=0?d[x][u-2]:0;
	f[x][u]=f[fa][u-1]-w+d[x][u];
	for(int i=head[x];i;i=edge[i].nxt)
		if(edge[i].to!=fa) calc(edge[i].to,x,u);
}
void work(int u){
	for(int i=head[1];i;i=edge[i].nxt)
		calc(edge[i].to,1,u);
}
int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int main(){
	n=read(),k=read();
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		ins(x,y),ins(y,x);
	}
	for(int i=1;i<=n;i++)
		a[i]=read(),d[i][0]=a[i];
	if(!k){
		for(int i=1;i<=n;i++)
			printf("%d\n",a[i]);
		return 0;
	}
	for(int i=1;i<=k;i++) dfs(1,0,i),f[1][i]=d[1][i];
	for(int i=1;i<=n;i++) f[i][0]=a[i];
	for(int i=1;i<=k;i++) work(i);
	for(int i=1;i<=n;i++) printf("%d\n",f[i][k]);
	return 0;
}
posted @ 2019-07-02 07:18  DQY_dqy  阅读(158)  评论(0编辑  收藏  举报