洛谷-P13736 [JOIGST 2025] 日本浮现 / Japan Emerges

洛谷-P13736 [JOIGST 2025] 日本浮现 / Japan Emerges

tag: 图论建模,Kruskal

给定 \(H\times W\) 网格,开始时有 $ N $ 格是陆地,其他是海洋,每天陆地会向下蔓延一格。问最少多少天以后,所有陆地连通。如下图:

\(1\le H,E\le2\times10^5\)\(2\le N\le\min\{HW,2\times10^5\}\)

统计从一个陆地网格到其下面(同一列或左右两列)的第一个陆地网格所需的时间。

将每一个陆地网格视为节点,向下蔓延所需时间为边权,向蔓延到的下一个陆地网格连边。

这样就好做了,一种想法是二分答案,使用所有边权小于等于 \(x\) 的边,验证是否能连通。

另一种想法,考虑一天一天过去,可使用的边权也在增加,这与最小生成树 Kruskal 的过程类似。

因此直接跑 Kruskal,最后一个加入的边的权值即为答案。

#include <bits/stdc++.h>
#define f(i, a, b) for (int i = (a); i <= (b); ++i)
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef vector<int> vi;
typedef vector<vector<int> > vvi;
typedef vector<pair<int, int> > vii;

void solve() {
    int h, w, n; cin >> h >> w >> n;
    vii p(n + 1);
    f(i, 1, n) cin >> p[i].fi >> p[i].se;
    sort(p.begin() + 1, p.end());
    vvi col(w + 1);
    f(i, 1, n) col[p[i].se].pb(i);

    struct Edge {
        int u, v, w;
        inline bool operator<(Edge const &o) const {
            return w < o.w;
        }
    };
    vector<Edge> e;
    vi ptr(w + 1, 0);
    f(i, 1, n) {
        f(j, p[i].se - 1, p[i].se + 1) {
            if (j < 1 || j > w) continue;
            while (ptr[j] < col[j].size() && p[col[j][ptr[j]]].fi < p[i].fi) {
                ++ptr[j];
            }
            if (j == p[i].se) ++ptr[j];
            if (ptr[j] >= col[j].size()) continue;
            int nxt = col[j][ptr[j]];
            e.pb((Edge){i, nxt, p[nxt].fi - p[i].fi - (p[i].se == p[nxt].se)});
        }
    }

    vi fa(n + 1);
    auto getfa = [&](auto &&self, int x) -> int {
        return x == fa[x] ? x : fa[x] = self(self, fa[x]);
    };
    iota(fa.begin() + 1, fa.end(), 1);

    int cnt = 1;
    sort(e.begin(), e.end());
    for (auto [u, v, w]: e) {
        int fu = getfa(getfa, u), fv = getfa(getfa, v);
        if (fu ^ fv) {
            fa[fu] = fv;
            ++cnt;
            if (cnt == n) {
                cout << w << '\n';
                return;
            }
        }
    }

    cout << "-1\n";

    return;
}

signed main() {
    cin.tie(0)->sync_with_stdio(false);

    int tt = 1;
    // cin >> tt;
    while (tt--) solve();

    return 0;
}
posted @ 2025-11-20 23:51  f2021ljh  阅读(0)  评论(0)    收藏  举报