现在的位置: 首页 > 综合 > 正文

BZOJ 2591 [Usaco 2012 Feb]Nearby Cows

2012年09月02日 ⁄ 综合 ⁄ 共 1208字 ⁄ 字号 评论关闭

BZOJ_2591

    由于K比较小,我们可以用f[i][j]表示距离第i个节点为j的所有节点的权值和,那么最后实际上就是对于特定的i输出sum{f[i][j]}。

    对于一个特定的f[i][j]来讲,一共由两部分构成,一部分路径来自于子节点,一部分路径来自于父节点,我们可以先从叶子节点开始向上dp,将来自于子节点的部分计算出来,再从根节点开始向下dp,将来自于父节点的部分累加上。

#include<stdio.h>
#include<string.h>
#define MAXD 100010
#define MAXM 200010
int N, K, first[MAXD], e, next[MAXM], v[MAXM], c[MAXD];
int f[MAXD][25], dp[MAXD][25];
void add(int x, int y)
{
    v[e] = y;
    next[e] = first[x], first[x] = e ++;    
}
void init()
{
    memset(first, -1, sizeof(first[0]) * (N + 1)), e = 0;
    for(int i = 1; i < N; i ++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y), add(y, x);
    }
    for(int i = 1; i <= N; i ++) scanf("%d", &c[i]);
}
int q[MAXD], fa[MAXD];
void solve()
{
    int rear = 0;
    q[rear ++] = 1, fa[1] = -1;
    for(int i = 0; i < rear; i ++)
    {
        int x = q[i];
        for(int j = first[x]; j != -1; j = next[j])
            if(v[j] != fa[x])
                fa[v[j]] = x, q[rear ++] = v[j];
    }
    for(int i = rear - 1; i >= 0; i --)
    {
        int x = q[i];
        memset(f[x], 0, sizeof(f[x][0]) * (K + 1));
        for(int j = first[x]; j != -1; j = next[j])
            if(v[j] != fa[x])
                for(int k = 1; k <= K; k ++)
                    f[x][k] += f[v[j]][k - 1];
        f[x][0] = c[x];
    }
    for(int i = 0; i < rear; i ++)
    {
        int x = q[i];
        for(int j = first[x]; j != -1; j = next[j])
            if(v[j] != fa[x])
            {
                int y = v[j];
                for(int k = K; k >= 1; k --)
                    f[y][k] += f[x][k - 1] - (k > 1 ? f[y][k - 2] : 0);    
            }
    }
    for(int i = 1; i <= N; i ++)
    {
        int ans = 0;
        for(int j = 0; j <= K; j ++) ans += f[i][j];
        printf("%d\n", ans);    
    }
}
int main()
{
    while(scanf("%d%d", &N, &K) == 2)
    {
        init();
        solve();    
    }
    return 0;    
}

 

 

抱歉!评论已关闭.