[USACO12FEB Gold]Nearby Cows 题解报告

[USACO12FEB Gold]Nearby Cows

问题描述

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

输入格式

第一行两个正整数\(n\)\(k\)

接下来 $ n−1$ 行,每行两个正整数 \(u\)\(v\),表示\(u\)\(v\) 之间有一条边。

最后 $ n$ 行,每行一个非负整数 \(c_i\) ,表示点权。

输出格式

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

样例输入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\)%的数据:\(1≤n≤10^5 ,1≤k≤20,0≤ci≤1000\)

求距离它不超过k的所有节点权值的和

首先想的是一个一个枚举

不知道数据允许不

啊,不可以(ˉ▽ˉ;)...

所以,我们来想一想另外的方法

???

万能的DP出场了!!!

我们可以尝试

\(d [i] [j]\)表示从\(i\)点开始向下\(j\)内权值之和

\(f[i] [j]\)代表从\(i\)点开始距离\(≤j\)的权值之和

\(d[i] [j]\)可以很容易算出来

对于一个点u,\(d[u][j]=C_{u}+∑_{v∈son_{u}}d[v][j-1]\)

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

这个方程式说父亲的信息+u向下的信息-无用信息

这里无用的信息就是\(d[u][j-2]\)

因为父亲的信息包括了从父亲往下的信息

而对于\(u\)来说,父亲往下\(j-1\)的点距离ta并没有\(j\)的距离

只有\(j-2\)的距离

所以需要将父亲往下的答案减去

所以\(f[fa[u]][j-1]-d[u][j-2]\)就是\(u\)往上\(j\)的权值之和

最后输出\(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;
}

完结撒花❀

★,°:.☆( ̄▽ ̄)/$:.°★ 。

posted @ 2022-06-06 17:16  _Youngxy  阅读(107)  评论(0)    收藏  举报