[USACO22DEC] Breakdown P 题解

T1 [USACO22DEC] Breakdown P

比较显然的一点是,一次加一条边/一次删一条边,显然转化,这是显然的一条套路。

这题的 K8,很有意思的数据范围,然后调用我们聪明的人类大脑得知需要用到折半搜索。所以我们只考虑 K4 的情况,令 st 表示折半搜索中考虑的起点。维护 1n 不超过 k 步的最短路 hi,以及任意两点间经过条边的最短路 fi,j。假若我们要更新 u,v,w,然后就是神奇的部分:

  • K=1,在 u=st 的情况下,更新 hv=w
  • K=2,对 1in,更新 himin(hi,fst,i)
  • K=3,同理,用 fst,i+w 更新 hi,其中 w 是两点间边权;
  • K=4,同理,用 fst,i+f 更新 hi,其中 f 是你处理好的 f

细节懒得说了,总之单次加边复杂度均摊 O(n)。然后就没了。

void cm(int &x, int y) {
    x = x < y ? x : y;
}
constexpr int MAXN = 305;
int n, k, w[MAXN][MAXN], ans[MAXN * MAXN];
struct {
    int u, v;
} del[MAXN * MAXN];
struct {
    int st, k;
    int w[MAXN][MAXN], f[MAXN][MAXN], h[MAXN];
    void init(int _k, int _st) {
        k = _k, st = _st;
        memset(w, 0x3f, sizeof(w));
        memset(f, 0x3f, sizeof(f));
        memset(h, 0x3f, sizeof(h));
        if (!k)h[st] = 0;
    }
    void add(int u, int v, int ww) {
        w[u][v] = ww;
        if (!k)return;
        if (k == 1)return u == st && (h[v] = ww), void();
        for (int i = 1; i <= n; ++i) {
            cm(f[i][v], w[i][u] + ww);
            cm(f[u][i], ww + w[v][i]);
        }
        if (k == 2)for (int i = 1; i <= n; ++i)cm(h[i], f[st][i]);
        else {
            auto p = k == 3 ? w : f;
            if (u == st)
                for (int i = 1; i <= n; ++i)
                    for (int j = 1; j <= n; ++j)
                        cm(h[j], f[st][i] + p[i][j]);
            else
                for (int i = 1; i <= n; ++i) {
                    cm(h[i], f[st][v] + p[v][i]);
                    cm(h[i], f[st][u] + p[u][i]);
                    cm(h[u], f[st][i] + p[i][u]);
                    cm(h[v], f[st][i] + p[i][v]);
                }
        }
    }
} s, t;

signed main() {
//	freopen("data.in","r",stdin);
    n = read(), k = read();
    for (int i = 1; i <= n; ++i)for (int j = 1; j <= n; ++j)w[i][j] = read();
    for (int i = 1; i <= n * n; ++i)del[i] = {read(), read()};
    s.init(floor(k * 0.5), 1), t.init(ceil(k * 0.5), n);
    for (int i = n * n; i; --i) {
        ans[i] = 1e9;
        for (int j = 1; j <= n; ++j)cm(ans[i], s.h[j] + t.h[j]);
        s.add(del[i].u, del[i].v, w[del[i].u][del[i].v]);
        t.add(del[i].v, del[i].u, w[del[i].u][del[i].v]);
    }
    for (int i = 1; i <= n * n; ++i)write(ans[i] == 1e9 ? -1 : ans[i]);
    return fw, 0;
}
posted @   Laoshan_PLUS  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示