$P3047 [USACO12FEB]$附近的牛$Nearby Cows$

\(Description\)

题面
题意是给你一颗\(n\)个节点的树和\(k(k\leq 20)\),每条边权是\(1\),告诉你\(n\)个点的点权,输出到点\(i\)距离\(\leq k\)的所有点的点权和

\(Solution\)

感觉很不可做,一开始考虑维护距离为\(k\)的点,然后跟着当前点往一个方向走,发现根本没法实现。
考虑到一维状态不够用,肯定要使用二维\(dp\),第一维已经达到了\(1e5\)的数据量,盲猜第二维是\(\leq k\)的数。
于是\(dp[i][j]\)表示到\(i\)点距离\(\leq j\)的点权和,考虑一个子节点是\(s\),如何进行转移。
若要求子节点的所有贡献都能转移到\(dp[i][j]\),一定要转移来的是距离不超过\(j-1\)的,因为从\(i-->s\)需要走一步,所以剩下走到最远只能走\(j-1\)
所以\(dp[i][j]+=dp[s][j-1](s\in son[i])\)
这样做向下找保证两个边界恰好相同,但向上找就会发现\(dp[s][j-1]\)\(s\)向上走\(j-1\)步,也就是走\(1\)步到\(i\),再从\(i\)往其他方向走\(j-2\)
看这张图

红色部分是加入的\(dp[s][j-1]\),我们需要消除红色部分超越父亲节点到其他节点的影响,所以每次\(+dp[s][j-1]-dp[i][j-2]\)即可
但最后注意到中间一部分(也就是\(i\)向外扩展\(j-2\))每次都被减去,最后没有加入中间部分答案,所以只需要再加一次\(dp[i][j-2]\)即可
有点类似容斥的思想
具体实现因为每次都要减去\(dp[i][j-2]\),所以统计完所有子树后\(-dp[i][j-2]*(son[i]-1)\)即可
但注意到一个问题,如果使用常规的\(dfs\)序父亲无法统计,于是根本不用\(dfs\),直接\(for\)循环所有节点和所有距离统计答案就行,但要注意枚举顺序的问题,假如外层先枚举节点,那么\(i=1,j=3\)时其他节点的\(j=2\)的情况都没被更新,这样\(dp\)肯定错了,所以换一换枚举顺序,外层先枚举\(j\)也就是距离即可

\(Code\)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define re register
#define maxn 100100
using namespace std;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct Edge{
    int v,nxt;
}e[maxn<<2];
int n,k,x,y,c[maxn],head[maxn],cnt;
int dp[maxn][25],du[maxn];
inline void add(int u,int v)
{
    e[++cnt].v=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
    du[u]++;
}
void DP()
{
    for(re int j=1;j<=k;++j)
        for(re int i=1;i<=n;++i)
        {
            for(re int p=head[i];p;p=e[p].nxt)
              dp[i][j]+=dp[e[p].v][j-1];
            if(j==1) dp[i][j]+=dp[i][0];
            else dp[i][j]-=dp[i][j-2]*(du[i]-1);
        }
}
int main()
{
    n=read(),k=read();
    for(re int i=1;i<n;++i)
    {
        x=read(),y=read();
        add(x,y);
        add(y,x);
    }
    for(re int i=1;i<=n;++i) c[i]=read(),dp[i][0]=c[i];
    DP();
    for(re int i=1;i<=n;++i) printf("%d\n",dp[i][k]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Liuz8848/p/11787629.html