제출 #1354675

#제출 시각아이디문제언어결과실행 시간메모리
1354675lehuydzEvacuation plan (IZhO18_plan)C++20
100 / 100
243 ms70960 KiB
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

const long long INF = 1e18;
const int MAXN = 100005;
const int LOG = 20;

int n, m, k, q;
vector<pair<int, long long>> adj[MAXN];
vector<pair<int, long long>> tree_adj[MAXN];
long long dist_npp[MAXN];

// Cấu trúc cạnh cho Kruskal
struct Edge {
    int u, v;
    long long w;
    bool operator<(const Edge& other) const {
        return w > other.w; // Sắp xếp giảm dần để tìm Cây khung lớn nhất
    }
};

vector<Edge> edges;

// Disjoint Set Union (DSU)
int parent_node[MAXN], sz[MAXN];
void make_set() {
    for (int i = 1; i <= n; ++i) {
        parent_node[i] = i;
        sz[i] = 1;
    }
}
int find_set(int v) {
    if (v == parent_node[v]) return v;
    return parent_node[v] = find_set(parent_node[v]);
}
bool union_sets(int a, int b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
        if (sz[a] < sz[b]) swap(a, b);
        parent_node[b] = a;
        sz[a] += sz[b];
        return true;
    }
    return false;
}

// Lowest Common Ancestor (LCA)
int up[MAXN][LOG];
long long min_w[MAXN][LOG];
int depth[MAXN];

void dfs(int u, int p, int d) {
    depth[u] = d;
    up[u][0] = p;
    for (int i = 1; i < LOG; ++i) {
        up[u][i] = up[up[u][i - 1]][i - 1];
        min_w[u][i] = min(min_w[u][i - 1], min_w[up[u][i - 1]][i - 1]);
    }

    for (auto edge : tree_adj[u]) {
        int v = edge.first;
        long long weight = edge.second;
        if (v != p) {
            min_w[v][0] = weight;
            dfs(v, u, d + 1);
        }
    }
}

// Truy vấn giá trị nhỏ nhất trên đường đi
long long query(int u, int v) {
    long long res = INF;
    if (depth[u] < depth[v]) swap(u, v);

    // Nâng u lên cùng độ sâu với v
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[up[u][i]] >= depth[v]) {
            res = min(res, min_w[u][i]);
            u = up[u][i];
        }
    }

    if (u == v) return res;

    // Nâng cả u và v lên gần LCA
    for (int i = LOG - 1; i >= 0; --i) {
        if (up[u][i] != up[v][i]) {
            res = min(res, min_w[u][i]);
            res = min(res, min_w[v][i]);
            u = up[u][i];
            v = up[v][i];
        }
    }

    // Xét nốt 2 cạnh nối u, v với LCA
    res = min({res, min_w[u][0], min_w[v][0]});
    return res;
}

int main() {
    // Tối ưu I/O cho Competitive Programming
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    if (!(cin >> n >> m)) return 0;

    for (int i = 0; i < m; ++i) {
        int u, v;
        long long w;
        cin >> u >> v >> w;
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
        edges.push_back({u, v, 0}); 
    }

    cin >> k;
    vector<int> npp(k);
    for (int i = 0; i < k; ++i) cin >> npp[i];

    // 1. Multi-source Dijkstra
    for (int i = 1; i <= n; ++i) dist_npp[i] = INF;
    priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;

    for (int i = 0; i < k; ++i) {
        dist_npp[npp[i]] = 0;
        pq.push({0, npp[i]});
    }

    while (!pq.empty()) {
        pair<long long, int> top = pq.top();
        pq.pop();
        long long d = top.first;
        int u = top.second;

        if (d > dist_npp[u]) continue;

        for (auto edge : adj[u]) {
            int v = edge.first;
            long long w = edge.second;
            if (dist_npp[v] > dist_npp[u] + w) {
                dist_npp[v] = dist_npp[u] + w;
                pq.push({dist_npp[v], v});
            }
        }
    }

    // 2. Maximum Spanning Tree (Kruskal)
    for (int i = 0; i < m; ++i) {
        edges[i].w = min(dist_npp[edges[i].u], dist_npp[edges[i].v]);
    }
    sort(edges.begin(), edges.end());

    make_set();
    for (auto edge : edges) {
        if (union_sets(edge.u, edge.v)) {
            tree_adj[edge.u].push_back({edge.v, edge.w});
            tree_adj[edge.v].push_back({edge.u, edge.w});
        }
    }

    // 3. Khởi tạo LCA & Mảng Sparse Table
    depth[0] = -1;
    for (int i = 0; i < LOG; ++i) {
        up[0][i] = 0;
        min_w[0][i] = INF;
    }
    dfs(1, 0, 0); // Giả sử đỉnh 1 luôn có trên đồ thị và làm gốc

    // 4. Trả lời truy vấn
    cin >> q;
    while (q--) {
        int u, v;
        cin >> u >> v;
        cout << query(u, v) << "\n";
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...