1. 程式人生 > 實用技巧 >[Usaco 2012 Feb]Nearby Cows

[Usaco 2012 Feb]Nearby Cows

題目

Description

Farmer John has noticed that his cows often move between nearby fields. Taking this into account, he wants to plant enough grass in each of his fields not only for the cows situated initially in that field, but also for cows visiting from nearby fields. Specifically, FJ's farm consists of N fields (1 <= N <= 100,000), where some pairs of fields are connected with bi-directional trails (N-1 of them in total). FJ has designed the farm so that between any two fields i and j, there is a unique path made up of trails connecting between i and j. Field i is home to C(i) cows, although cows sometimes move to a different field by crossing up to K trails (1 <= K <= 20). FJ wants to plant enough grass in each field i to feed the maximum number of cows, M(i), that could possibly end up in that field -- that is, the number of cows that can potentially reach field i by following at most K trails. Given the structure of FJ's farm and the value of C(i) for each field i, please help FJ compute M(i) for every field i.


FJ發現他的牛經常跑到附近的草地去吃草,FJ準備給每個草地種足夠的草供這個草地以及附近草地的奶牛來吃。FJ有N個草地(1<=N<=100000),有N-1條雙向道路連線這些草地,FJ精心設計了這些道路使每兩個草地有且僅有一條簡單路徑連線。第i個草場有Ci頭牛,有時候奶牛會走過K條道路到其他草地吃草。FJ想知道每個草場最多可能有的奶牛數量Mi,即所有走過K條道路後可能到達i的奶牛總數。

Input

* 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)

Output

* Lines 1..N: Line i should contain the value of M(i).

Sample Input

6 2
5 1
3 6
2 4
2 1
3 2
1
2
3
4
5
6

Sample Output

15
21
16
10
8
11

思路

這一題的題意大概是,求每個點往外k 條邊距離,所有點的權值和;

那麼很明顯是一道樹形dp的題;

我們可以不斷地用子節點更新父節點;

很顯然父節點延伸的距離 += 子節點延伸的距離 -1 ;

那麼 子節點延伸的距離 += 父節點延伸的距離 -1 ;

也就可以遍歷兩遍;

dp[x][j]+=dp[xx][j-1]; dp[xx][j]+=dp[x][j-1];

但是我們發現

第一次遍歷時,到 x 距離為2的點,加上了了到 xx 距離為1 的點;

第二次遍歷時,dp[xx][j] 加上 dp[x][j-1] 時

舉個例子,第一次遍歷 dp[1][2]+ =dp[2][1];

第二次遍歷 dp[2][3]+ =dp[1][2];

在第一次遍歷時 dp[1][2] 包括了 dp[2][1] 2的子樹權值;

然鵝 ans在統計dp[2][3] 的時候也加上了 dp[2][1] 2的子樹權值;

第二次遍歷 dp[2][3] 又加上了 dp[2][1];

所以需要簡單容斥一下;

for(re ll j=q;j>=2;j--)
    dp[xx][j]-=dp[xx][j-2];

這樣就ok了

程式碼

#include<bits/stdc++.h>
#define re register
typedef long long ll;
using namespace std;
inline ll read()
{
    ll a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}//好用的快讀 
ll n,q;
ll head[200010],dp[200010][21];
struct ljj
{
    ll to,stb;
}a[200010];
ll s=0;
inline void insert(ll x,ll y)
{
    s++;
    a[s].stb=head[x];
    a[s].to=y;
    head[x]=s;
}
inline void dfs(ll x,ll fa)
{
    for(re ll i=head[x];i;i=a[i].stb)
    {
        ll xx=a[i].to;
        if(xx==fa)
            continue;
        dfs(xx,x);
        for(re ll j=1;j<=q;j++)
            dp[x][j]+=dp[xx][j-1];//第一遍dp 
    }
}
inline void dfs1(ll x,ll fa)
{
    for(re ll i=head[x];i;i=a[i].stb)
    {
        ll xx=a[i].to;
        if(xx==fa)
            continue;
        //在第一次遍歷時 dp[1][2] 包括了 dp[2][1] 2的子樹權值;
        //然鵝  ans在統計dp[2][3] 的時候也加上了 dp[2][1]  2的子樹權值;
        //第二次遍歷 dp[2][3] 又加上了 dp[2][1];
        //所以需要簡單容斥一下; 
        for(re ll j=q;j>=2;j--)
            dp[xx][j]-=dp[xx][j-2];//簡單容斥 
        for(re ll j=1;j<=q;j++)
            dp[xx][j]+=dp[x][j-1];//第二遍dp 
        dfs1(xx,x);
    }
}
int main()
{
    n=read();q=read(); 
    for(re ll i=1;i<n;i++)
    {
        ll x=read(),y=read();
        insert(x,y);
        insert(y,x);
    }
    for(re ll i=1;i<=n;i++)
        dp[i][0]=read();//每個節點往外0距離,就是它本身的權值; 
    dfs(1,0);
    dfs1(1,0);
    for(re ll i=1;i<=n;i++)
    {
        ll ans=0;
        for(re ll j=0;j<=q;j++)
            ans+=dp[i][j];//ans統計答案 
        printf("%lld\n",ans);
    }
    return 0;
}

[Usaco 2012 Feb]Nearby Cows