【牛客练习赛55-E】:树【树形dp】

题目:

牛客练习赛55 - E:树

题意:

给定一颗边权全为 1 的树,求两两点之间距离的平方的和

分析:

如果是求两两之间距离的和,直接树形dp算每条边的贡献即可;现在题目要求距离平方的和,还是考虑树形dp枚举每条边计算每条边的贡献,套路地将平方展开看一下,比如算: (a+b+c)*(a+b+c) = a^2 + a*(b+c) + b^2 + b*(a+c) + c^2 + c*(a+b),发现对于每一条边它的贡献都是一样的计算方式,边权又为 1,那么每条边的贡献就是经过这条边的所有路径的长度和,这个只需要维护子树节点的个数和子树节点到根的距离和就能 O(1) 快速计算,树形dp枚举每条边就做完了

 代码:

#include 
 
#define x first
#define y second
#define pii pair
#define sz(x) (int)(x).size()
#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long LL;
const int maxn = 1e6+16;
const int mod = 998244353;
inline int read(){
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){if(c == '-')f=-1; c=getchar();}
    while(isdigit(c)) {x = x*10+c-'0'; c = getchar();}
    return x * f;
}
inline void write(int x){
    if (x >= 10) write(x / 10);
    putchar(x % 10 + '0');
}
int head[maxn],tot,x,y,n;
struct edge{
    int to,nxt;
}e[maxn<<1];
inline void add(int u,int v){
    e[++tot] = (edge){v,head[u]};
    head[u] = tot;
}
LL sz[maxn],sum[maxn],ans;
void dfs1(int x,int fa){
    sz[x] = 1;
    for(int i = head[x];i>0;i = e[i].nxt){
        int v = e[i].to; if(v == fa) continue;
        dfs1(v,x); sz[x] += sz[v];
        sum[x] = (sum[x]+sum[v]+sz[v])%mod;
    }
}
void dfs2(int x,int fa,LL cnt,LL len){
    for(int i = head[x];i>0;i = e[i].nxt){
        int v = e[i].to; if(v == fa) continue;
        LL newcnt = (cnt+sz[x]-sz[v]+mod)%mod;
        LL newlen = ((len+sum[x]-sum[v]-sz[v])%mod+mod)%mod;
        ans += newcnt*sz[v]+newlen*sz[v]+sum[v]*newcnt;
        ans %= mod;
        dfs2(v,x,newcnt,(newlen+newcnt)%mod);
    }
}
int main(){
    n = read();
    for(int i = 1;i < n; ++i){
        x = read(), y = read();
        add(x,y); add(y,x);
    }
    dfs1(1,0); dfs2(1,0,0,0);
    write(ans*2%mod);
    return 0;
}

 

你可能感兴趣的:(题解----牛客网,动态规划----树形dp)