제출 #1291996

#제출 시각아이디문제언어결과실행 시간메모리
1291996hahaEvacuation plan (IZhO18_plan)C++20
0 / 100
431 ms46584 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INFLL = (ll)4e18;
const int MAXN = 100000 + 5;
const int LOG = 20;

int n, m;
vector<pair<int,int>> g[MAXN];
ll dis_arr[MAXN];

struct Edge {
    int u, v;
    ll w;
};
vector<Edge> edges;

// DSU for Kruskal
int dsu[MAXN], dsu_sz[MAXN];
int find_set(int x){
    if(dsu[x]==x) return x;
    return dsu[x] = find_set(dsu[x]);
}
bool union_set(int a, int b){
    a = find_set(a); b = find_set(b);
    if(a==b) return false;
    if(dsu_sz[a] < dsu_sz[b]) swap(a,b);
    dsu[b] = a;
    dsu_sz[a] += dsu_sz[b];
    return true;
}

// MST adjacency (undirected)
vector<pair<int,ll>> mst[MAXN];

// HLD / LCA structures
int parentArr[MAXN];
int up[MAXN][LOG];
int depthArr[MAXN];
int sz[MAXN];

int ChainHead[MAXN], ChainID[MAXN], posInBase[MAXN], baseArr[MAXN];
int CurChain = 0, CurPos = 0;
ll aVal[MAXN]; // stores dis value for each node

// segment tree (min)
vector<ll> seg;
int baseN = 0;

void dijkstra_multi_source(const vector<int>& srcs){
    for(int i=1;i<=n;i++) dis_arr[i] = INFLL;
    priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;
    for(int s: srcs){
        dis_arr[s] = 0;
        pq.push({0, s});
    }
    while(!pq.empty()){
        auto cur = pq.top(); pq.pop();
        ll d = cur.first; int u = cur.second;
        if(d != dis_arr[u]) continue;
        for(auto &e : g[u]){
            int v = e.first; int w = e.second;
            if(dis_arr[v] > d + w){
                dis_arr[v] = d + w;
                pq.push({dis_arr[v], v});
            }
        }
    }
}

// DFS to prepare sizes, up[v][0], depth, parentArr
void dfs_prep(int u, int p){
    parentArr[u] = p;
    up[u][0] = p;
    sz[u] = 1;
    for(auto &e : mst[u]){
        int v = e.first;
        ll w = e.second; // weight stored but we use aVal for node values
        if(v == p) continue;
        depthArr[v] = depthArr[u] + 1;
        dfs_prep(v, u);
        sz[u] += sz[v];
    }
}

// HLD: assign chain/head/pos/baseArr
void HLD(int u, int p){
    if(ChainHead[CurChain] == 0) ChainHead[CurChain] = u;
    ChainID[u] = CurChain;
    posInBase[u] = ++CurPos;
    baseArr[CurPos] = u;

    int heavy = -1;
    for(auto &e : mst[u]){
        int v = e.first;
        if(v == p) continue;
        if(heavy == -1 || sz[v] > sz[heavy]) heavy = v;
    }
    if(heavy != -1) HLD(heavy, u);
    for(auto &e : mst[u]){
        int v = e.first;
        if(v == p || v == heavy) continue;
        CurChain++;
        HLD(v, u);
    }
}

// segment tree helpers
void seg_init(int nbase){
    baseN = nbase;
    seg.assign(4 * (baseN+5), INFLL);
}
void seg_build(int id, int l, int r){
    if(l == r){
        int node = baseArr[l];
        seg[id] = aVal[node];
        return;
    }
    int mid = (l+r)/2;
    seg_build(id*2, l, mid);
    seg_build(id*2+1, mid+1, r);
    seg[id] = min(seg[id*2], seg[id*2+1]);
}
ll seg_query(int id, int l, int r, int ql, int qr){
    if(ql > r || qr < l) return INFLL;
    if(ql <= l && r <= qr) return seg[id];
    int mid = (l+r)/2;
    return min(seg_query(id*2, l, mid, ql, qr), seg_query(id*2+1, mid+1, r, ql, qr));
}

// LCA (binary lifting) - requires up[][] precomputed
int lca(int u, int v){
    if(depthArr[u] < depthArr[v]) swap(u,v); // u deeper
    int diff = depthArr[u] - depthArr[v];
    for(int j=0;j<LOG;j++){
        if(diff & (1<<j)) u = up[u][j];
    }
    if(u == v) return u;
    for(int j=LOG-1;j>=0;j--){
        if(up[u][j] != up[v][j]){
            u = up[u][j];
            v = up[v][j];
        }
    }
    return up[u][0];
}

// Query min of aVal on path u--v excluding LCA node itself (matches original HLD intention)
// Returns INFLL if no nodes considered (e.g., u==v)
ll query_path_min_exclude_lca(int u, int v){
    int p = lca(u,v);
    ll ans = INFLL;

    // bring u up to p, chain by chain
    while(ChainID[u] != ChainID[p]){
        int head = ChainHead[ChainID[u]];
        ans = min(ans, seg_query(1, 1, baseN, posInBase[head], posInBase[u]));
        // jump to parent of head
        u = up[head][0];
    }
    // same chain: exclude p itself
    if(posInBase[p] + 1 <= posInBase[u]){
        ans = min(ans, seg_query(1, 1, baseN, posInBase[p] + 1, posInBase[u]));
    }

    // bring v up to p
    while(ChainID[v] != ChainID[p]){
        int head = ChainHead[ChainID[v]];
        ans = min(ans, seg_query(1, 1, baseN, posInBase[head], posInBase[v]));
        v = up[head][0];
    }
    if(posInBase[p] + 1 <= posInBase[v]){
        ans = min(ans, seg_query(1, 1, baseN, posInBase[p] + 1, posInBase[v]));
    }
    return ans;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for(int i=1;i<=n;i++){
        g[i].clear();
        mst[i].clear();
    }

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

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

    // multi-source dijkstra
    dijkstra_multi_source(sources);

    // build edges with weight = min(dist[u], dist[v]) (only once per undirected edge)
    edges.clear();
    for(int u=1; u<=n; u++){
        for(auto &e : g[u]){
            int v = e.first;
            if(u < v){
                edges.push_back({u, v, min(dis_arr[u], dis_arr[v])});
            }
        }
    }

    sort(edges.begin(), edges.end(), [](const Edge &A, const Edge &B){
        return A.w > B.w; // maximum spanning
    });

    // init dsu
    for(int i=1;i<=n;i++){
        dsu[i] = i; dsu_sz[i] = 1;
    }

    // Kruskal -> MST (maximum spanning forest)
    for(auto &e : edges){
        if(union_set(e.u, e.v)){
            mst[e.u].push_back({e.v, e.w});
            mst[e.v].push_back({e.u, e.w});
        }
    }

    // prepare arrays
    for(int i=1;i<=n;i++){
        parentArr[i] = 0;
        depthArr[i] = 0;
        sz[i] = 0;
        for(int j=0;j<LOG;j++) up[i][j] = 0;
        ChainHead[i] = 0;
        ChainID[i] = 0;
        posInBase[i] = 0;
        baseArr[i] = 0;
        aVal[i] = dis_arr[i]; // node value
    }
    CurChain = 1; CurPos = 0;

    // run DFS prep and HLD for all components (forest)
    for(int i=1;i<=n;i++){
        if(depthArr[i] == 0){
            depthArr[i] = 1;
            dfs_prep(i, 0);
            HLD(i, 0);
            CurChain++;
        }
    }

    // build binary lifting up[][] using parentArr (we set up[][0] = parentArr)
    // note: up[][] currently has up[v][0] = parentArr[v] = set in dfs_prep (which used parent)
    for(int j=1;j<LOG;j++){
        for(int v=1; v<=n; v++){
            int mid = up[v][j-1];
            if(mid == 0) up[v][j] = 0;
            else up[v][j] = up[mid][j-1];
        }
    }

    // build segtree on base size = CurPos
    int bN = CurPos;
    if(bN == 0){
        // no nodes? safety
        bN = n;
    }
    seg_init(bN);
    seg_build(1, 1, bN);

    // queries
    int Qq;
    cin >> Qq;
    while(Qq--){
        int u,v; cin >> u >> v;
        // if u and v not in same MST component, there's no path in the MST
        if(find_set(u) != find_set(v)){
            cout << -1 << '\n';
            continue;
        }
        ll ans = query_path_min_exclude_lca(u, v);
        if(ans == INFLL) cout << -1 << '\n';
        else cout << ans << '\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...