제출 #373337

#제출 시각아이디문제언어결과실행 시간메모리
373337arujbansal물병 (JOI14_bottle)C++17
100 / 100
1996 ms274140 KiB
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <array>
#include <stack>
#include <queue>
#include <random>
#include <numeric>
#include <functional>
#include <chrono>
#include <utility>
#include <iomanip>
#include <assert.h>

using namespace std;

void dbg_out() { cerr << endl; }
template<typename Head, typename... Tail>
void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); }
#define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__)

#define rng_init mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define rng_seed(x) mt19937 rng(x)
#define all(x) (x).begin(), (x).end()
#define sz(x) (int) (x).size()
#define int long long

struct Edge {
    int u, v, w;

    Edge(int u, int v, int w) : u(u), v(v), w(w) {}

    bool operator<(const Edge &b) const {
        return w < b.w;
    }
};

const int MXN = 2100, INF = 1e15, MXP = 4e5 + 5, MXK = 20;
using pii = pair<int, int>;

int H, W, P, Q;
int grid[MXN][MXN], dist[MXN][MXN], bfs_par[MXN][MXN];

bool valid(int i, int j) {
    if (i < 1 || i > H || j < 1 || j > W) return false;
    if (grid[i][j] < 0) return false;

    return true;
}

int par[MXP], cost[MXP], tin[MXP], tout[MXP], binlift[MXK][MXP];
vector<int> g[MXP];
int new_node, timer;

int get(int x) {
    if (par[x] == x) return x;
    return par[x] = get(par[x]);
}

void add_edge(int u, int v) {
    g[u].push_back(v);
    g[v].push_back(u);
}

void unite(int x, int y, int w) {
    x = get(x), y = get(y);
    if (x == y) return;

    cost[new_node] = w;

    add_edge(x, new_node);
    add_edge(y, new_node);

    par[x] = new_node;
    par[y] = new_node;

    new_node++;
}

void dfs(int u, int p) {
    tin[u] = timer++;

    for (int k = 1; k < MXK; k++)
        binlift[k][u] = binlift[k - 1][binlift[k - 1][u]];

    for (const auto &v : g[u]) {
        if (v == p) continue;

        binlift[0][v] = u;

        dfs(v, u);
    }

    tout[u] = timer - 1;
}

bool is_anc(int v, int u) {
    return (tin[v] <= tin[u] && tout[v] >= tout[u]);
}

int get_lca(int u, int v) {
    if (is_anc(u, v)) return u;
    if (is_anc(v, u)) return v;

    for (int i = MXK - 1; i >= 0; i--) {
        if (is_anc(binlift[i][u], v)) continue;
        u = binlift[i][u];
    }

    return binlift[0][u];
}

void solve() {
    cin >> H >> W >> P >> Q;

    for (int i = 0; i <= H + 2; i++) {
        for (int j = 0; j <= W + 2; j++) {
            grid[i][j] = -1;
            dist[i][j] = INF;
        }
    }

    for (int i = 1; i <= H; i++) {
        for (int j = 1; j <= W; j++) {
            char x;
            cin >> x;

            if (x == '.') grid[i][j] = 0;
        }
    }

    deque<pii> dq;

    for (int i = 1; i <= P; i++) {
        int x, y;
        cin >> x >> y;

        grid[x][y] = i;

        dq.emplace_back(x, y);
        dist[x][y] = 0;
        bfs_par[x][y] = i;
    }

    int pos[4][2] = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};

    vector<Edge> edges;

    while (!dq.empty()) {
        auto cur = dq.front();
        dq.pop_front();

        int x = cur.first, y = cur.second;

        for (const auto &[dx, dy] : pos) {
            int nx = dx + x, ny = dy + y;

            if (!valid(nx, ny)) continue;

            if (dist[nx][ny] < INF) {
                if (bfs_par[x][y] == bfs_par[nx][ny]) continue;
                edges.emplace_back(bfs_par[x][y], bfs_par[nx][ny], dist[x][y] + dist[nx][ny]);
            } else {
                int wt = (grid[nx][ny] == 0);

                if (wt == 0) dq.emplace_front(nx, ny);
                else dq.emplace_back(nx, ny);

                dist[nx][ny] = dist[x][y] + wt;
                bfs_par[nx][ny] = bfs_par[x][y];
            }
        }
    }

    // for (int i = 1; i <= H; i++) {
    //     for (int j = 1; j <= W; j++) {
    //         cout << bfs_par[i][j] << " ";
    //     }

    //     cout << "\n";
    // }

    sort(all(edges));

    // for (const auto &[u, v, w] : edges) {
    //     cout << u << " " << v << " " << w << "\n";
    // }
    
    for (int i = 0; i < MXP; i++) {
        par[i] = i;
        cost[i] = INF;
    }

    new_node = P + 1;

    for (const auto &[u, v, w] : edges) {
        unite(u, v, w);
    }

    for (int i = 1; i < new_node; i++) {
        if (get(i) == i) add_edge(i, 0);
    }

    dfs(0, -1);

    // for (int i = 0; i < MXP; i++) {
    //     for (const auto &v : g[i]) {
    //         cout << i << " " << v << "\n";
    //     }
    // }

    // dbg(get_lca(1, 2));

    while (Q--) {
        int u, v;
        cin >> u >> v;

        int lca = get_lca(u, v);
        int ans = cost[lca];

        cout << (ans < INF ? ans : -1) << "\n";
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int TC = 1;
    // cin >> TC;
    while (TC--) solve();
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...