专栏文章

P5628 【AFOI-19】面基

P5628题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minlyzex
此快照首次捕获于
2025/12/02 04:35
3 个月前
此快照最后确认于
2025/12/02 04:35
3 个月前
查看原文
不是哥们,这题有什么好容斥的?直接换根啊!
观察到 n×kn\times k 很小,设计 fi,jf_{i,j} 表示子树 ii 中距 iijj 的边的贡献总和。一个 dfs 可以快速解决。
我们应该要解决以每个点为根的答案的 max\max
对于以 uu 为根的树,答案应为 i=0kfu,i\sum^{k}_{i=0} f_{u,i},然后枚举所有 uvu\to v,先在 fuf_u 中减去 fvf_v 的贡献,同时更新子树大小,然后再在 fvf_v 中加入 fuf_u
代码很少很清晰。
CPP
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define eb emplace_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll MOD=1e9+7;
// head
const int N=3e4+5,M=205;
int n,k;
vector<vector<int>> G(N);
int sz[N],f[N][M];
void dfs(int u,int fa)
{
    sz[u]=1;
    for(auto v:G[u]){
        if(v==fa) continue;
        dfs(v,u);
        sz[u]+=sz[v];
        for(int i=1;i<=k;i++) f[u][i]+=f[v][i-1];
        f[u][0]+=sz[v]*(n-sz[v]);
    }
}
int ans;
void dfs2(int u,int fa)
{
    int sum=0;
    for(int i=0;i<=k;i++) sum+=f[u][i];
    ans=max(ans,sum);
    for(auto v:G[u]){
        if(v==fa) continue;
        for(int i=1;i<=k;i++) f[u][i]-=f[v][i-1];
        f[u][0]-=sz[v]*(n-sz[v]);
        sz[u]-=sz[v],sz[v]+=sz[u];
        for(int i=1;i<=k;i++) f[v][i]+=f[u][i-1];
        f[v][0]+=sz[u]*(n-sz[u]);
        dfs2(v,u);
        for(int i=1;i<=k;i++) f[v][i]-=f[u][i-1];
        f[v][0]-=sz[u]*(n-sz[u]);
        sz[v]-=sz[u],sz[u]+=sz[v];
        for(int i=1;i<=k;i++) f[u][i]+=f[v][i-1];
        f[u][0]+=sz[v]*(n-sz[v]);
    }
}
signed main() 
{
    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    cin>>n>>k;
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        G[u].pb(v);
        G[v].pb(u);
    }
    dfs(1,0);
    dfs2(1,0);
    cout<<ans<<'\n';
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...