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;
}