[CF70E] Information Reform 题解

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

[CF70E] Information Reform

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

\(\bcancel{n\le 180}\color{red}n\le 5000\),存在 \(O(n^2)\) 做法。

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

考虑状态设计 \(f_{u, i}\) 表示考虑 \(u\) 子树内点的贡献,且距离 \(u\) 最近的点是 \(i(i\in \text{subtree}_u)\)\(g_{u, i}\) 表示考虑 \(u\) 子树内点的贡献,且距离 \(u\) 最近的点是 \(i(i\notin \text{subtree}_u)\),辅助数组 \(F_u = \min_i f_{u, i}\)

考虑转移,设 \(p\)\(u\) 的儿子,且 \(i\)\(p\) 的子树里面,则

\[\begin{aligned} f_{u, u} &= k + \sum_{(u, v)\in \text E}\min(F(v), g_{v, u})\\ f_{u, i} &= D(u, i) + f_{p, i} + \sum_{v \ne p,(u, v)\in \text E} \min(F(v), g_{v, i})\\ g_{u, i} &= D(u, i) + \sum_{(u, v)\in \text E} \min(F_v, g_{v, i}) \end{aligned} \]

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

点我呀(/▽\)
#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 @ 2025-02-09 16:08  MoyouSayuki  阅读(17)  评论(0)    收藏  举报
:name :name