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

随便定一个根,设\(f[i][j]\)表示只考虑子树,距离为\(j\)的权值和,\(g[i][j]\)表示考虑子树和父树,距离为\(j\)的权值和,显然答案可以用\(g\)表示

\(f[p][0]=w[p]\)
\(f[p][k]=\sum f[q][k-1]\)
\(g[1][k]=f[1][k]\)
\(g[p][0]=w[p]\)

\(g\)的计算,考虑容斥

\[g[q][k] =\sum( f[q][k] + g[p][k-1] - f[q][k-2]) \]

注意特判掉\(k=1\)

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 100005;
vector <int> G[N];
int n,k,vis[N],f[N][22],g[N][22],w[N];

void dfs1(int p) {
    vis[p]=1;
    for(int i=0;i<G[p].size();i++) {
        int q=G[p][i];
        if(vis[q]) continue;
        dfs1(q);
        for(int j=1;j<=k;j++)
            f[p][j]+=f[q][j-1];
    }
}

void dfs2(int p) {
    vis[p]=1;
    for(int i=0;i<G[p].size();i++) {
        int q=G[p][i];
        if(vis[q]) continue;
        for(int j=1;j<=k;j++)
            g[q][j]+=f[q][j]+g[p][j-1]-(j>1?1:0)*f[q][j-2];
        dfs2(q);
    }
}

signed main() {
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<n;i++) {
        int t1,t2;
        scanf("%lld%lld",&t1,&t2);
        G[t1].push_back(t2);
        G[t2].push_back(t1);
    }
    for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
    for(int i=1;i<=n;i++) f[i][0]=g[i][0]=w[i];
    dfs1(1);
    for(int i=1;i<=k;i++) g[1][i]=f[1][i];
    memset(vis,0,sizeof vis);
    dfs2(1);
    for(int i=1;i<=n;i++) {
        int ans = 0;
        for(int j=0;j<=k;j++) ans+=g[i][j];
        printf("%lld\n",ans);
    }
}

相关文章:

  • 2021-12-02
  • 2021-12-21
  • 2022-12-23
  • 2022-01-29
  • 2021-08-25
  • 2021-09-18
  • 2022-12-23
  • 2021-12-08
猜你喜欢
  • 2021-08-07
  • 2021-09-30
  • 2022-12-23
  • 2022-01-16
  • 2022-12-23
  • 2022-02-14
相关资源
相似解决方案