Submission #757784

#TimeUsernameProblemLanguageResultExecution timeMemory
757784taherToll (BOI17_toll)C++17
100 / 100
222 ms49640 KiB
#include <bits/stdc++.h>

using namespace std;

template<typename T, class F = function<T(const T&, const T&)>>
class SparseTable {
  public:
  int n;
  vector<vector<T>> mat;
  F func;

  SparseTable(const vector<int>& a, const F& f) : func(f) {
    n = (int) a.size();
    mat.resize(n);
    int max_log = 32 - __builtin_clz(n);
    mat[0] = a;
    for (int j = 1; j < max_log; j++) {
      mat[j].resize(n - (1 << j) + 1);
      for (int i = 0; i <= (n - (1 << j)); i++) {
        mat[j][i] = func(mat[j - 1][i], mat[j - 1][i + (1 << (j - 1))]);
      }
    }
  }

  T get(int from, int to) {
    assert(from <= to && from >= 0 && to <= n - 1);
    int lg = 32 - __builtin_clz(to - from + 1) - 1;
    return func(mat[lg][from], mat[lg][to - (1 << lg) + 1]);
  }
};

const int N = 50000;
const int inf = 1000000000;

int dp[N];
bool inQue[N];
vector<array<int, 2>> adj[N];
vector<array<int, 2>> rAdj[N];

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int k, n, m, q;
  cin >> k >> n >> m >> q;

  int p = (n + k - 1) / k;
  vector<vector<int>> bucket(p);

  for (int i = 0; i < n; i++) {
    bucket[i / k].push_back(i);
  }

  for (int i = 0; i < n; i++) {
    inQue[i] = false;
    dp[i] = inf;
  }

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

  vector<vector<vector<vector<pair<int, int>>>>> pts(p * 2, vector<vector<vector<pair<int, int>>>> (k, vector<vector<pair<int, int>>> (2)));

  auto Solve = [&](int midPoint, int cnt) {
    for (int each = 0; each < (int) bucket[midPoint].size(); each++) {
      int x = bucket[midPoint][each];
      dp[x] = 0;
      pts[cnt][each][0].emplace_back(x, 0);
      pts[cnt][each][1].emplace_back(x, 0);
      for (int it = x - 1; it >= 0; it--) {
        if (inQue[it / k]) {
          break;
        }
        for (auto y : adj[it]) {
          dp[it] = min(dp[it], dp[y[0]] + y[1]);
        }
        pts[cnt][each][0].emplace_back(it, dp[it]);
      }
      reverse(pts[cnt][each][0].begin(), pts[cnt][each][0].end());
      for (int it = x - 1; it >= 0; it--) {
        if (inQue[it / k]) {
          break;
        }
        dp[it] = inf;
      }
      for (int it = x + 1; it < n; it++) {
        if (inQue[it / k]) {
          break;
        }
        for (auto y : rAdj[it]) {
          dp[it] = min(dp[it], dp[y[0]] + y[1]);
        }
        pts[cnt][each][1].emplace_back(it, dp[it]);
      }
      for (int it = x; it < n; it++) {
        if (inQue[it / k]) {
          break;
        }
        dp[it] = inf;
      }
    }
  };

  vector<int> at(p, inf);

  auto Divide = [&]() {
    int cnt = 0;
    queue<array<int, 2>> que;
    que.push({0, p - 1});
    while (!que.empty()) {
      auto t = que.front();
      que.pop();
      int low = t[0];
      int high = t[1];
      if (low >= high) {
        continue;
      }
      int midPoint = low + (high - low) / 2;
      Solve(midPoint, cnt);
      inQue[midPoint] = true;
      at[midPoint] = cnt;
      cnt++;
      que.push({low, midPoint});
      que.push({midPoint + 1, high});
    }
  };

  Divide();

  SparseTable<int> st(at, [&](int i, int j) {
    return min(i, j);
  });

  while (q--) {
    int u, v;
    cin >> u >> v;
    int b0 = u / k;
    int b1 = v / k;
    if (b0 == b1) {
      cout << -1 << '\n';
    } else {
      int ans = inf;
      int cnt = st.get(b0, b1);
      for (int each = 0; each < k; each++) {
        if (pts[cnt][each][0].empty()) {
          break;
        }
        int it0 = lower_bound(pts[cnt][each][0].begin(), pts[cnt][each][0].end(), make_pair(u, -inf)) - pts[cnt][each][0].begin();
        int it1 = lower_bound(pts[cnt][each][1].begin(), pts[cnt][each][1].end(), make_pair(v, -inf)) - pts[cnt][each][1].begin();
        if (it0 < (int) pts[cnt][each][0].size() && it1 < (int) pts[cnt][each][1].size()) {
          if (pts[cnt][each][0][it0].first == u && pts[cnt][each][1][it1].first == v) {
            ans = min(ans, pts[cnt][each][0][it0].second + pts[cnt][each][1][it1].second);
          }
        }
      }
      if (ans < inf) {
        cout << ans << '\n';
      } else {
        cout << -1 << '\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...