牛客练习赛55 E.树 树形dp

Posted kaka0010

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客练习赛55 E.树 树形dp相关的知识,希望对你有一定的参考价值。

原题链接:https://ac.nowcoder.com/acm/contest/2927/E

题意

有一棵树,设 d i s ( x , y ) dis(x,y) dis(x,y)表示x到y的距离,求

∑ i = 1 n ∑ j = 1 n d i s 2 ( i , j ) \\sum_{i=1}^{n}\\sum_{j=1}^{n}dis^2(i,j) i=1nj=1ndis2(i,j)

分析

树上路径有一种计算方法

d i s ( x , y ) = d e p [ x ] + d e p [ y ] − 2 ∗ d e p [ l c a ( x , y ) ] dis(x,y)=dep[x]+dep[y]-2*dep[lca(x,y)] dis(x,y)=dep[x]+dep[y]2dep[lca(x,y)]

那么

d i s 2 ( x , y ) = ( d e p [ x ] + d e p [ y ] − 2 ∗ d e p [ l c a ( x , y ) ] ) 2 dis^2(x,y)=(dep[x]+dep[y]-2*dep[lca(x,y)])^2 dis2(x,y)=(dep[x]+dep[y]2dep[lca(x,y)])2

= d e p [ x ] 2 + d e p [ y ] 2 + 2 ∗ d e p [ x ] d e p [ y ] − 4 ∗ d e p [ l c a ( x , y ) ] ( d e p [ x ] + d e p [ y ] ) + 4 ∗ d e p [ l c a ( x , y ) ] 2 =dep[x]^2+dep[y]^2+2*dep[x]dep[y]-4*dep[lca(x,y)](dep[x]+dep[y])+4*dep[lca(x,y)]^2 =dep[x]2+dep[y]2+2dep[x]dep[y]4dep[lca(x,y)](dep[x]+dep[y])+4dep[lca(x,y)]2

对于式子的前三项,可以在处理完所有深度之后O(n)计算得到,接着就是怎么算后面的部分

我们假设lca(x,y)=a,然后对于每一个a,我们对树进行遍历。对于a节点来说,假设b1,b2…bm是a节点的儿子节点,那么点对个数num可以轻松得到
n u m = s i z [ a ] ∗ s i z [ a ] − ∑ i = 1 s i z [ b i ] ∗ s i z [ b i ] num=siz[a]*siz[a]-\\sum_{i=1}siz[b_{i}]*siz[b_{i}] num=siz[a]siz[a]i=1siz[bi]siz[bi]

易得 ∑ 4 ∗ d e p [ a ] 2 = 4 ∗ d e p [ a ] 2 ∗ n u m \\sum4*dep[a]^2=4*dep[a]^2*num 4dep[a]2=4dep[a]2num

然后考虑 ∑ 4 ∗ d e p [ a ] ( d e p [ x ] + d e p [ y ] ) \\sum 4*dep[a](dep[x]+dep[y]) 4dep[a](dep[x]+dep[y]),首先突破口就是所有点对的深度和,我们可以把深度和转化一下, d e p [ x ] + d e p [ y ] = 2 ∗ d e p [ a ] + d i s ( x , y ) dep[x]+dep[y]=2*dep[a]+dis(x,y) dep[x]+dep[y]=2dep[a]+dis(x,y),其中dis(x,y)就可以从每个子树开始出发,到除子树外所有点的距离和即 r e s = ∑ ( s i z [ a ] − b i ) ∗ s u m [ b i ] res = \\sum (siz[a]-b_{i})*sum[b_{i}] res=(siz[a]bi)sum[bi],sum是所有子树节点到该节点的距离之和。

可以推出 ∑ 4 ∗ d e p [ a ] ( d e p [ x ] + d e p [ y ] ) = 4 ∗ r e s ∗ d e p [ a ] \\sum 4*dep[a](dep[x]+dep[y])=4*res*dep[a] 4dep[a](dep[x]+dep[y])=4resdep[a]

Code

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define re register
typedef long long ll;
typedef pair<ll, ll> PII;
typedef unsigned long long ull;
const int N = 1e6 + 10, M = 1e6 + 5, INF = 0x3f3f3f3f;
const int MOD = 998244353;
vector<int> g[N];
ll siz[N], dep[N], sum[N], ans;
int n;
void dfs1(int x, int fa) {
    siz[x] = 1, dep[x] = dep[fa] + 1, sum[x] = dep[x];
    for (auto v : g[x]) {
        if (v == fa) continue;
        dfs1(v, x);
        siz[x] += siz[v];
        sum[x] += sum[v];
    }
}
void dfs2(int x, int fa) {
    ll num = siz[x] * siz[x] % MOD;
    ll res = 2 * dep[x] * siz[x] % MOD;
    for (auto v : g[x]) {
        if (v == fa) continue;
        dfs2(v, x);
        num = (num - siz[v] * siz[v] % MOD + MOD) % MOD;
        res = (res + 2 * sum[v] * (siz[x] - siz[v]) % MOD) % MOD;
    }
    ans = (ans + 4 * dep[x] % MOD * dep[x] % MOD * num % MOD - 4 * dep[x] % MOD * res % MOD + MOD) % MOD;
}
void solve() {
    cin >> n;
    for (int i = 1; i <= n-1; i ++) {
        int u, v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs1(1, 0);
    dfs2(1, 0);
    ll tmp = 0;
    for (int i = 1; i <= n; i++) ans = (ans + 2 * dep[i] * dep[i] % MOD * n % MOD) % MOD, tmp = (tmp + dep[i]) % MOD;
    ans = (ans + 2 * tmp * tmp % MOD) % MOD;
    cout << ans << endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}


以上是关于牛客练习赛55 E.树 树形dp的主要内容,如果未能解决你的问题,请参考以下文章

牛客练习赛83 E.牛客推荐系统开发之标签重复度

E. Paint the Tree(树形dp)

牛客练习赛55E树

牛客练习赛55E树

2021牛客多校4 - Rebuild Tree(树形dp)

牛客练习赛87 E.贪吃蛇(构造矩阵快速幂)