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

题目链接:https://ac.nowcoder.com/acm/contest/2927/E
在这里插入图片描述
思路:
在这里插入图片描述
对于节点4来说,它到其他点的距离dis[i] ∑ d i s ( 4 , i ) 2 = d i s [ 1 ] 2 + d i s [ 2 ] 2 + d i s [ 3 ] 2 + d i s [ 4 ] 2 + d i s [ 5 ] 2 + d i s [ 6 ] 2 + d i s [ 7 ] 2 + d i s [ 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
∑ d i s ( 5 , i ) 2 = ( d i s [ 1 ] + 1 ) 2 + ( d i s [ 2 ] + 1 ) 2 + ( d i s [ 3 ] + 1 ) + ( d i s [ 4 ] + 1 ) + ( d i s [ 5 ] − 1 ) 2 + ( d i s [ 6 ] − 1 ) 2 + ( d i s [ 7 ] − 1 ) 2 + ( d i s [ 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
∑ d i s ( 5 , i ) 2 = d i s [ 1 ] 2 + d i s [ 2 ] 2 + d i s [ 3 ] 2 + d i s [ 4 ] 2 + d i s [ 5 ] 2 + d i s [ 6 ] 2 + d i s [ 7 ] 2 + d i s [ 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 ( d i s [ 1 ] + d i s [ 2 ] + d i s [ 3 ] + d i s [ 4 ] ) − 2 ( d i s [ 5 ] + d i s [ 6 ] + d i s [ 7 ] + d i s [ 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

∑ d i s ( 5 , i ) 2 = ∑ d i s ( 4 , i ) 2 + 2 ( d i s [ 1 ] + d i s [ 2 ] + d i s [ 3 ] + d i s [ 4 ] ) − 2 ( d i s [ 5 ] + d i s [ 6 ] + d i s [ 7 ] + d i s [ 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
我们发现:

s 1 = d i s [ 5 ] + d i s [ 6 ] + d i s [ 7 ] + d i s [ 8 ] 是 5 的 子 树 ( 包 含 5 ) 到 4 的 距 离 = 5 所 有 子 树 到 5 的 距 离 和 + 4 的 子 节 点 个 数 : 一 次 d f s 就 可 以 求 所 有 节 点 的 s 1 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=55+4:dfss1

s 2 = d i s [ 5 ] + d i s [ 6 ] + d i s [ 7 ] + d i s [ 8 ] 是 除 了 5 的 子 树 的 其 他 点 到 4 的 距 离 和 。 这 里 不 好 求 , 如 果 我 们 求 出 所 有 点 到 4 的 距 离 s 3 那 么 就 可 以 得 到 : s 2 = s 3 − s 1 s2=dis[5]+dis[6]+dis[7]+dis[8] 是除了5的子树的其他点到4的距离和。这里不好求,如果我们求出所有点到4的距离s3那么就可以得到:s2=s3-s1 s2=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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值