P3047

[USACO12FEB]Nearby Cows G

题目描述

给你一棵 \(n\) 个点的树,点带权,对于每个节点求出距离它不超过 \(k\) 的所有节点权值和 \(m_i\)

输入格式

* Line 1: Two space-separated integers, N and K.

* Lines 2..N: Each line contains two space-separated integers, i and j (1 <= i,j <= N) indicating that fields i and j are directly connected by a trail.

* Lines N+1..2N: Line N+i contains the integer C(i). (0 <= C(i) <= 1000)

第一行两个正整数 \(n,k\)
接下来 \(n-1\) 行,每行两个正整数 \(u,v\),表示 \(u,v\) 之间有一条边。
最后 \(n\) 行,每行一个非负整数 \(c_i\),表示点权。

输出格式

* Lines 1..N: Line i should contain the value of M(i).

输出 \(n\) 行,第 \(i\) 行一个整数表示 \(m_i\)

样例 #1

样例输入 #1

6 2 
5 1 
3 6 
2 4 
2 1 
3 2 
1 
2 
3 
4 
5 
6

样例输出 #1

15 
21 
16 
10 
8 
11

提示

There are 6 fields, with trails connecting (5,1), (3,6), (2,4), (2,1), and (3,2). Field i has C(i) = i cows.

Field 1 has M(1) = 15 cows within a distance of 2 trails, etc.

【数据范围】
对于 \(100\%\) 的数据:\(1 \le n \le 10^5\)\(1 \le k \le 20\)\(0 \le c_i \le 1000\)

最开始想的是怎么直接在dfs中递归求解 Σ

其实考虑的不应该是 所有的<=k的Σ 而应该关心 f[i][j] 最后统计答案的时候累加一遍即可

很容易想到 f[u][j]与 f[v][j-1]有密切的关联

只是 要求的是距离为j的 也就是除了往子树方向走 还有往父亲节点方向走的 所以不好转移

先思考简单部分 f[u][j]:u的子树内 dis==j 的Σval

直接dfs更新答案即可(注意初始化 f[u][0]=c[u])

最关键的步骤是怎么加上父亲节点方向的权值

可以这么想:既然我们要加上父亲方向的 那么父亲u的更新肯定在v之前(否则还是原来只求出来的往子树方向走的Σval)

所以 用 u 更新 v !!!!!!

思考:怎么操作?

f[v][j]+=Σf[u]j-1

看似正确 其实算重复了一小部分 即u往v的方向距离为j-1的部分(即与v相距j-2的部分) 所以要剪掉 但是不能用 u来算了 但是我们v还没有更新 所以先 f[v][j]-=f[v][j-2] 然后再 f[v][j]+=Σf[u][j-1]

最后统计 i:1~n Σf[i][0~k]即为答案

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int n,k,c[N];
struct Tree {
	int nxt,to;
} edge[N<<1];
int head[N],cnt;
inline void add(int u,int v) {
	cnt++;
	edge[cnt].to=v;
	edge[cnt].nxt=head[u];
	head[u]=cnt;
}
int dep[N],fa[N],f[N][25];//f[i][j]:int i's subtree dis==j  's Σval
void dfs1(int u,int fat) {
	fa[u]=fat,dep[u]=dep[fat]+1;
	for(int i=head[u]; i; i=edge[i].nxt) {
		int v=edge[i].to;
		if(v==fat)continue;
		dfs1(v,u);
		for(int j=1; j<=k; j++)
			f[u][j]+=f[v][j-1];
	}
}
void dfs2(int u,int fat) {
	for(int i=head[u]; i; i=edge[i].nxt) {
		int v=edge[i].to;
		if(v==fat)continue;
		for(int j=k; j>=2; j--)
			f[v][j]-=f[v][j-2];
		for(int j=1; j<=k; j++)
			f[v][j]+=f[u][j-1];
		dfs2(v,u);
	}
}
signed main() {
	ios::sync_with_stdio(false);
	cin>>n>>k;
	for(int i=1; i<n; i++) {
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	for(int i=1; i<=n; i++)cin>>c[i];
	for(int i=1; i<=n; i++)f[i][0]=c[i];
	dfs1(1,0);
	dfs2(1,0);
	for(int i=1; i<=n; i++) {
		int ans=0;
		for(int j=0; j<=k; j++)ans+=f[i][j];
		cout<<ans<<"\n";
	}
	return 0;
}
posted @ 2023-05-15 20:51  N0zoM1z0  阅读(6)  评论(0编辑  收藏  举报