[换根dp] CF771C
一个稍有不同的解法?
题意
给出一棵有
思路
容易想到换根
如何解决呢?发现不好对每个点单独讨论,也就是说最终式子最好含有
我们知道
根据上式,有:
诶,这样就出现
考虑怎么求
具体的,记
复杂度
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5, K = 5;
int n, k, g[N], f[N], son[N], u, v;
int G[N][K], F[N][K], Gs[N][K], ans;
vector<int> to[N];
inline void dfs1(int u, int fa){
son[u] = 1;
for(auto v : to[u])
if(v ^ fa){
dfs1(v, u);
son[u] += son[v];
g[u] += g[v] + son[v];
for(int c = 0; c < k; ++c)
G[u][(c + 1) % k] += G[v][c], Gs[u][c] += G[v][c];
++G[u][1 % k], ++Gs[u][0];
}
}
inline void dfs2(int u, int fa){
if(fa){
f[u] = f[fa] + n - son[fa] + 1;
f[u] += g[fa] - g[u] - son[u] + son[fa] - son[u] - 1;
for(int c = 0; c < k; ++c){
F[u][(c + 1) % k] += F[fa][c];
F[u][(c + 2) % k] += Gs[fa][c] - G[u][c] - (c == 0);
}
++F[u][1 % k];
}
for(auto v : to[u])
if(v ^ fa) dfs2(v, u);
}
signed main(){
cin >> n >> k;
for(int i = 1; i < n; ++i)
scanf("%lld%lld", &u, &v), to[u].push_back(v), to[v].push_back(u);
dfs1(1, 0), dfs2(1, 0);
for(int i = 1; i <= n; ++i){
int res = g[i] + f[i];
for(int c = 1; c < k; ++c)
res += (k - c) * (G[i][c] + F[i][c]);
ans += res / k;
}
cout << ans / 2;
return 0;
}