[CF70E] Information Reform 题解

通常和到关键点的距离有关的一些树形 DP,初见可能比较棘手,容易在状态设计上卡住。

[CF70E] Information Reform

设置若干关键点,使得所有点到距离最近的关键点的代价之和最小,ij 的代价定义为 D(i,j)=ddist(i,j),需要输出方案。

n180n5000,存在 O(n2) 做法。

仔细思考,由于题目中的距离代价很鬼畜,没法拆贡献,一种可能性是我们需要对于一个点确切找到它对应的关键点。

考虑状态设计 fu,i 表示考虑 u 子树内点的贡献,且距离 u 最近的点是 i(isubtreeu)gu,i 表示考虑 u 子树内点的贡献,且距离 u 最近的点是 i(isubtreeu),辅助数组 Fu=minifu,i

考虑转移,设 pu 的儿子,且 ip 的子树里面,则

fu,u=k+(u,v)Emin(F(v),gv,u)fu,i=D(u,i)+fp,i+vp,(u,v)Emin(F(v),gv,i)gu,i=D(u,i)+(u,v)Emin(Fv,gv,i)

记录前驱即可完成这道题。

点我呀(/▽\)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#define int long long
using namespace std;
const int N = 3000 + 10, INF = 1e18, mod = 998244353;

int n, m, k, c[N], f[N][N], F[N], g[N][N], ft[N], dep[N], dis[N], lca[N][N], dfn[N], sz[N], timestamp, pos[N], d[N], to[N];
vector<int> G[N];
void dfs(int u, int fa) {
    ft[u] = fa, dep[u] = dep[fa] + 1, dfn[u] = ++ timestamp, sz[u] = 1, pos[timestamp] = u;
    for(auto v : G[u]) if(v != fa) dfs(v, u), sz[u] += sz[v];
}
void LCA(int u) {
    lca[u][u] = u;
    for(auto v : G[u]) {
        if(v == ft[u]) continue;
        LCA(v);
        for(int i = dfn[u]; i < dfn[v]; i ++)
            for(int j = dfn[v]; j < dfn[v] + sz[v]; j ++)
                lca[pos[i]][pos[j]] = lca[pos[j]][pos[i]] = u;
    }
}
int dist(int a, int b) {
    return d[dep[a] + dep[b] - 2 * dep[lca[a][b]]];
}
int sum[N], coef[N];
void dfs2(int u) {
    for(auto v : G[u]) if(v != ft[u]) dfs2(v);
    for(int i = 1; i <= n; i ++) sum[i] = 0, coef[i] = 0;    
    for(auto v : G[u]) {
        if(v == ft[u]) continue;
        for(int i = 1; i <= n; i ++) {
            sum[i] += min(g[v][i], F[v]);
            if(lca[i][v] == v) coef[i] = f[v][i] - min(g[v][i], F[v]);
        }
    }
    f[u][u] = k + sum[u];
    F[u] = f[u][u], to[u] = u;
    for(int i = 1; i <= n; i ++) if(u != i) {
        if(lca[u][i] == u) {
            f[u][i] = dist(u, i) + sum[i] + coef[i], F[u] = min(F[u], f[u][i]);
            if(f[u][i] == F[u]) to[u] = i;
        }
        else {
            g[u][i] = sum[i] + dist(u, i);
        }
    }
}
int bel[N];
void print(int u, int i) {
    if(i == -1 || (g[u][i] >= F[u])) bel[u] = to[u];
    else bel[u] = i;
    for(auto v : G[u]) if(v != ft[u]) print(v, bel[u]);
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> k;
    for(int i = 1; i < n; i ++) cin >> d[i];
    for(int i = 1, a, b, c; i < n; i ++) cin >> a >> b, G[a].push_back(b), G[b].push_back(a);
    dfs(1, 0), LCA(1);
    dfs2(1); 
    cout << F[1] << '\n';
    print(1, -1);
    for(int i = 1; i <= n; i ++) cout << bel[i] << ' '; cout << '\n';
    return 0;
}
posted @   MoyouSayuki  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
:name :name
点击右上角即可分享
微信分享提示