Submission #1285048

#TimeUsernameProblemLanguageResultExecution timeMemory
1285048kaysanToll (BOI17_toll)C++20
100 / 100
59 ms10372 KiB
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define fi first
#define se second
#define pb push_back

const ll INF = (ll)4e18;

int K, N, M, Q;
int leafCount; // number of base matrices = max(0, L-1)
int segSize;
vector<vector<ll>> seg; // segment tree nodes: each node stores a KxK matrix in row-major

// identity matrix for min-plus semiring
vector<ll> identity_matrix(){
    vector<ll> I(K*K, INF);
    for(int i=0;i<K;i++) I[i*K + i] = 0;
    return I;
}

// multiply A ⊗ B in min-plus semiring. A,B are KxK row-major.
vector<ll> multiply_mat(const vector<ll>& A, const vector<ll>& B){
    vector<ll> C(K*K, INF);
    for(int i=0;i<K;i++){
        int base_i = i*K;
        for(int k=0;k<K;k++){
            ll aik = A[base_i + k];
            if(aik == INF) continue;
            int base_k = k*K;
            for(int j=0;j<K;j++){
                ll bkj = B[base_k + j];
                if(bkj == INF) continue;
                ll cand = aik + bkj;
                ll &dst = C[base_i + j];
                if(cand < dst) dst = cand;
            }
        }
    }
    return C;
}

// build segtree from base array of matrices (size = leafCount)
void build_segtree(const vector<vector<ll>>& base){
    int need = max(1, leafCount);
    segSize = 1;
    while(segSize < need) segSize <<= 1;
    seg.assign(2*segSize, identity_matrix());
    for(int i=0;i<leafCount;i++) seg[segSize + i] = base[i];
    for(int i=segSize-1;i>=1;i--){
        seg[i] = multiply_mat(seg[2*i], seg[2*i+1]); // left ⊗ right
    }
}

// range product [l, r] inclusive over base indices (0..leafCount-1)
vector<ll> range_product(int l, int r){
    if(l > r) return identity_matrix();
    l += segSize; r += segSize;
    vector<ll> leftRes = identity_matrix();
    vector<ll> rightRes = identity_matrix();
    while(l <= r){
        if(l & 1){
            leftRes = multiply_mat(leftRes, seg[l++]);
        }
        if(!(r & 1)){
            rightRes = multiply_mat(seg[r--], rightRes);
        }
        l >>= 1; r >>= 1;
    }
    return multiply_mat(leftRes, rightRes);
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    if(!(cin >> K >> N >> M >> Q)) return 0;

    int L = (N + K - 1) / K;
    leafCount = max(0, L - 1);

    vector<vector<ll>> base(leafCount, vector<ll>(K*K, INF));
    for(int i=0;i<M;i++){
        int a,b; ll t; cin >> a >> b >> t;
        if(a < 0 || a >= N || b < 0 || b >= N) continue;
        int la = a / K;
        int lb = b / K;
        if(lb != la + 1) continue; // only edges to next layer kept
        int pa = a % K;
        int pb = b % K;
        int idx = pa * K + pb;
        base[la][idx] = min(base[la][idx], t);
    }

    build_segtree(base);

    for(int qi=0; qi<Q; qi++){
        int a,b; cin >> a >> b;
        if(a < 0 || a >= N || b < 0 || b >= N){
            cout << -1 << '\n';
            continue;
        }
        int sa = a / K, sb = b / K;
        int pa = a % K, pb = b % K;
        if(sa == sb){
            if(a == b) cout << 0 << '\n';
            else cout << -1 << '\n';
            continue;
        }
        if(sa > sb){
            cout << -1 << '\n';
            continue;
        }
        if(leafCount == 0){
            cout << -1 << '\n';
            continue;
        }
        int L_from = sa;
        int L_to = sb - 1;
        if(L_from < 0) L_from = 0;
        if(L_to >= leafCount){ cout << -1 << '\n'; continue; }
        vector<ll> P = range_product(L_from, L_to);
        ll ans = P[pa * K + pb];
        if(ans >= INF/2) 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...