[USACO12FEB Gold]Nearby Cows
问题描述
给你一棵 n n n 个点的树,点带权,对于每个节点求出距离它不超过 k k k 的所有节点权值和 m i m_i mi。
输入格式
第一行两个正整数 n n n, k k k。
接下来 $ n−1$ 行,每行两个正整数 u u u, v v v,表示 u u u, v v v 之间有一条边。
最后 $ n$ 行,每行一个非负整数 c i c_i ci ,表示点权。
输出格式
输出 n n n 行,第 $ i$ 行一个整数表示 m i m_i mi。
样例输入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
数据范围
对于 100 100 100%的数据: 1 ≤ n ≤ 1 0 5 , 1 ≤ k ≤ 20 , 0 ≤ c i ≤ 1000 1≤n≤10^5 ,1≤k≤20,0≤ci≤1000 1≤n≤105,1≤k≤20,0≤ci≤1000
求距离它不超过k的所有节点权值的和
首先想的是一个一个枚举
不知道数据允许不
啊,不可以(ˉ▽ˉ;)…
所以,我们来想一想另外的方法
???
万能的DP出场了!!!
我们可以尝试
设 d [ i ] [ j ] d [i] [j] d[i][j]表示从 i i i点开始向下 j j j内权值之和
f [ i ] [ j ] f[i] [j] f[i][j]代表从 i i i点开始距离 ≤ j ≤j ≤j的权值之和
d [ i ] [ j ] d[i] [j] d[i][j]可以很容易算出来
对于一个点u, d [ u ] [ j ] = C u + ∑ v ∈ s o n u d [ v ] [ j − 1 ] d[u][j]=C_{u}+∑_{v∈son_{u}}d[v][j-1] d[u][j]=Cu+∑v∈sonud[v][j−1]
而 f [ i ] [ j ] f[i] [j] f[i][j]也可以得出, f [ u ] [ j ] = f [ f a [ u ] ] [ j − 1 ] − d [ u ] [ j − 2 ] + d [ u ] [ j ] f[u][j]=f[fa[u]][j-1]-d[u][j-2]+d[u][j] f[u][j]=f[fa[u]][j−1]−d[u][j−2]+d[u][j]
这个方程式说父亲的信息+u向下的信息-无用信息
这里无用的信息就是 d [ u ] [ j − 2 ] d[u][j-2] d[u][j−2]
因为父亲的信息包括了从父亲往下的信息
而对于 u u u来说,父亲往下 j − 1 j-1 j−1的点距离ta并没有 j j j的距离
只有 j − 2 j-2 j−2的距离
所以需要将父亲往下的答案减去
所以 f [ f a [ u ] ] [ j − 1 ] − d [ u ] [ j − 2 ] f[fa[u]][j-1]-d[u][j-2] f[fa[u]][j−1]−d[u][j−2]就是 u u u往上 j j j的权值之和
最后输出 f [ i ] [ k ] f[i] [k] f[i][k]就行了
code
#include<bits/stdc++.h>
using namespace std;
const int N=100002;
int n,k,cnt=0,x,y;
int hd[N],c[N],d[N][22],f[N][22];
struct Node {
int nxt,to;
} tr[N*2];
void dfs(int x,int fa,int u) {
d[x][u]+=c[x];
for(int i=hd[x]; i; i=tr[i].nxt) {
if(tr[i].to==fa) continue;
d[x][u]+=d[tr[i].to][u-1];
dfs(tr[i].to,x,u);
}
}
void dfsb(int x,int fa,int u) {
int w;
if(u>=2) w=d[x][u-2];
else w=0;
f[x][u]=f[fa][u-1]-w+d[x][u];
for(int i=hd[x]; i; i=tr[i].nxt){
if(tr[i].to!=fa){
dfsb(tr[i].to,x,u);
}
}
}
void add(int x,int y) {
tr[++cnt].nxt=hd[x];
tr[cnt].to=y;
hd[x]=cnt;
}
int main() {
scanf("%d%d",&n,&k);
for(int i=1; i<n; i++) {
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1; i<=n; i++) {
scanf("%d",&c[i]);
d[i][0]=f[i][0]=c[i];
}
if(!k) {
for(int i=1; i<=n; i++) {
printf("%d\n",c[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<=k; i++) {
for(int j=hd[1];j;j=tr[j].nxt){
dfsb(tr[j].to,1,i);
}
}
for(int i=1; i<=n; i++) {
printf("%d\n",f[i][k]);
}
return 0;
}
完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★ 。