ENFP-T型人格患者|

_Youngxy

园龄:3年7个月粉丝:5关注:28

[USACO12FEB Gold]Nearby Cows 题解报告

[USACO12FEB Gold]Nearby Cows

问题描述

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

输入格式

第一行两个正整数nk

接下来 n1 行,每行两个正整数 uv,表示uv 之间有一条边。

最后 n 行,每行一个非负整数 ci ,表示点权。

输出格式

输出 n 行,第 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%的数据:1n1051k200ci1000

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

首先想的是一个一个枚举

不知道数据允许不

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

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

???

万能的DP出场了!!!

我们可以尝试

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

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

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

对于一个点u,d[u][j]=Cu+vsonud[v][j1]

f[i][j]也可以得出,f[u][j]=f[fa[u]][j1]d[u][j2]+d[u][j]

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

这里无用的信息就是d[u][j2]

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

而对于u来说,父亲往下j1的点距离ta并没有j的距离

只有j2的距离

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

所以f[fa[u]][j1]d[u][j2]就是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;
}

完结撒花❀

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

本文作者:Yvette的博客

本文链接:https://www.cnblogs.com/yvette1217/p/16348976.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _Youngxy  阅读(78)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示