牛客练习赛55 -树-所有点对距离的平方和

本文深入探讨了一种基于树形结构的动态规划算法,通过详细分析节点间距离和子树属性,提出了一种高效求解特定问题的方法。利用深度优先搜索(DFS)策略,文章展示了如何动态维护节点到其子树及其它节点的距离之和,实现了一次遍历即可获得所有节点的解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://ac.nowcoder.com/acm/contest/2927/E
在这里插入图片描述
思路:
在这里插入图片描述
对于节点4来说,它到其他点的距离dis[i] ∑dis(4,i)2=dis[1]2+dis[2]2+dis[3]2+dis[4]2+dis[5]2+dis[6]2+dis[7]2+dis[8]2\sum dis(4, i)^2=dis[1]^{2}+dis[2]^{2}+dis[3]^{2}+dis[4]^{2}+dis[5]^{2}+dis[6]^{2}+dis[7]^{2}+dis[8]^{2}dis(4,i)2=dis[1]2+dis[2]2+dis[3]2+dis[4]2+dis[5]2+dis[6]2+dis[7]2+dis[8]2
如果根据dfs转移给子树的时候能够开始求出这个值,那么就可以dfs一次得到答案。
对于下一个点5
∑dis(5,i)2=(dis[1]+1)2+(dis[2]+1)2+(dis[3]+1)+(dis[4]+1)+(dis[5]−1)2+(dis[6]−1)2+(dis[7]−1)2+(dis[8]−1)2\sum dis(5, i)^2=(dis[1]+1)^{2}+(dis[2]+1)^{2}+(dis[3]+1)+(dis[4]+1)+(dis[5]-1)^{2}+(dis[6]-1)^{2}+(dis[7]-1)^{2}+(dis[8]-1)^{2} dis(5,i)2=(dis[1]+1)2+(dis[2]+1)2+(dis[3]+1)+(dis[4]+1)+(dis[5]1)2+(dis[6]1)2+(dis[7]1)2+(dis[8]1)2
∑dis(5,i)2=dis[1]2+dis[2]2+dis[3]2+dis[4]2+dis[5]2+dis[6]2+dis[7]2+dis[8]2\sum dis(5, i)^2=dis[1]^{2}+dis[2]^{2}+dis[3]^{2}+dis[4]^{2}+dis[5]^{2}+dis[6]^{2}+dis[7]^{2}+dis[8]^{2} dis(5,i)2=dis[1]2+dis[2]2+dis[3]2+dis[4]2+dis[5]2+dis[6]2+dis[7]2+dis[8]2
+2(dis[1]+dis[2]+dis[3]+dis[4])−2(dis[5]+dis[6]+dis[7]+dis[8])+n+2(dis[1]+dis[2]+dis[3]+dis[4]) - 2(dis[5]+dis[6]+dis[7]+dis[8])+n+2(dis[1]+dis[2]+dis[3]+dis[4])2(dis[5]+dis[6]+dis[7]+dis[8])+n

∑dis(5,i)2=∑dis(4,i)2+2(dis[1]+dis[2]+dis[3]+dis[4])−2(dis[5]+dis[6]+dis[7]+dis[8])+n\sum dis(5, i)^2=\sum dis(4, i)^2+2(dis[1]+dis[2]+dis[3]+dis[4]) - 2(dis[5]+dis[6]+dis[7]+dis[8])+n dis(5,i)2=dis(4,i)2+2(dis[1]+dis[2]+dis[3]+dis[4])2(dis[5]+dis[6]+dis[7]+dis[8])+n
我们发现:

s1=dis[5]+dis[6]+dis[7]+dis[8]是5的子树(包含5)到4的距离=5所有子树到5的距离和+4的子节点个数:一次dfs就可以求所有节点的s1 s1=dis[5]+dis[6]+dis[7]+dis[8] 是5的子树(包含5)到4的距离=5所有子树到5的距离和+4的子节点个数:一次dfs就可以求所有节点的s1s1=dis[5]+dis[6]+dis[7]+dis[8]5(5)4=55+4:dfss1

s2=dis[5]+dis[6]+dis[7]+dis[8]是除了5的子树的其他点到4的距离和。这里不好求,如果我们求出所有点到4的距离s3那么就可以得到:s2=s3−s1s2=dis[5]+dis[6]+dis[7]+dis[8] 是除了5的子树的其他点到4的距离和。这里不好求,如果我们求出所有点到4的距离s3那么就可以得到:s2=s3-s1s2=dis[5]+dis[6]+dis[7]+dis[8]544s3:s2=s3s1

我们在向下转移到4节点时,s3的改变为4上面所有的点距离+1(边4-5)5包含自己的子孙节点个数-1。

那么就可以动态维护了。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int mod=998244353;

vector<int> v[1000005];
LL siz[1000005];//子节点个数
LL sum[1000005];//子树到自己的距离和
LL d[1000005];//所有点到节点1的距离
LL s[1000005];//每个点到其他所有点的距离和
int n;
void dfs1(int u, int fa, int dis){//维护siz sum

    d[u]=dis;
    for(int i=0; i<v[u].size(); i++){
        int to=v[u][i];
        if(to!=fa){
            dfs1(to, u, dis+1);
            sum[u]+=(sum[to]+siz[to]);
            siz[u]+=siz[to];
        }
    }
    siz[u]+=1;
}

void dfs2(int u, int fa, LL s3){

    for(int i=0; i<v[u].size(); i++){
        int to=v[u][i];
        if(to!=fa){
            s[to]=s[u];
            LL s1=s3-sum[to]-siz[to];
            s1%=mod;
            LL s2=sum[to]+siz[to];
            s2%=mod;
            s[to]+=2*s1+n;
            s[to]-=2*s2;
            while(s[to]<0){
                s[to]=(s[to]+mod)%mod;
            }
            dfs2(to, u, s3+n-2*siz[to]);
        }
    }
}

int main()
{
    scanf("%d", &n);
    for(int i=1; i<n; i++){
        int a, b;
        scanf("%d%d", &a, &b);
        v[a].push_back(b);
        v[b].push_back(a);
    }
    dfs1(1, -1, 0);
    for(int i=2; i<=n; i++){//计算出1的值
        s[1]+=d[i]*d[i]%mod;
    }
    dfs2(1, -1, sum[1]);//动态转移
    LL ans=0;
    for(int i=1; i<=n; i++){
        ans=(ans+s[i])%mod;
    }
    cout<<ans<<endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值