牛客练习赛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=1∑nj=1∑ndis2(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]−2∗dep[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]−2∗dep[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+2∗dep[x]dep[y]−4∗dep[lca(x,y)](dep[x]+dep[y])+4∗dep[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=1∑siz[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 ∑4∗dep[a]2=4∗dep[a]2∗num
然后考虑 ∑ 4 ∗ d e p [ a ] ( d e p [ x ] + d e p [ y ] ) \\sum 4*dep[a](dep[x]+dep[y]) ∑4∗dep[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]=2∗dep[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] ∑4∗dep[a](dep[x]+dep[y])=4∗res∗dep[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的主要内容,如果未能解决你的问题,请参考以下文章