Problem p00386 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int(i) = 0; (i) < (int)(n); ++(i))
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout << #x " = " << ((x)) << endl
template <class T, class U>
ostream &operator<<(ostream &o, const pair<T, U> &p) {
  o << "(" << p.fi << "," << p.se << ")";
  return o;
}
template <class T> ostream &operator<<(ostream &o, const vector<T> &v) {
  o << "[";
  for (T t : v) {
    o << t << ",";
  }
  o << "]";
  return o;
}

// ノードの個数
const int MAX_V = 100000;
// ダブリングに必要なサイズ(log(MAX_V))
const int MAX_LOG_V = 17;
// 木の隣接リスト表現
vector<int> G[MAX_V];
// 根のノード番号
int root = 0;

// 親を2^k回辿って到達するノード(根を通り過ぎる場合,-1)
int parent[MAX_LOG_V][MAX_V];
// 根からの深さ
int depth[MAX_V];

// 現在vに注目、親はp、深さd
void lca_dfs(int v, int p, int d) {
  parent[0][v] = p;
  depth[v] = d;
  rep(i, G[v].size()) {
    if (G[v][i] != p) { // 親でなければ子
      lca_dfs(G[v][i], v, d + 1);
    }
  }
}

// 初期化
void lca_init(int V) {
  // parent[0]とdepthの初期化
  lca_dfs(root, -1, 0);
  // parentの初期化
  for (int k = 0; k + 1 < MAX_LOG_V; ++k) {
    for (int v = 0; v < V; ++v) {
      if (parent[k][v] < 0)
        parent[k + 1][v] = -1;
      else
        parent[k + 1][v] = parent[k][parent[k][v]];
    }
  }
}

// uとvのLCAを求める
int lca(int u, int v) {
  // uとvの深さが同じになるまで親を辿る
  if (depth[u] > depth[v])
    swap(u, v);
  for (int k = 0; k < MAX_LOG_V; ++k) {
    if ((depth[v] - depth[u]) >> k & 1)
      v = parent[k][v];
  }
  if (u == v)
    return u;
  // 二分探索でLCAを求める
  for (int k = MAX_LOG_V - 1; k >= 0; --k) {
    if (parent[k][u] != parent[k][v]) {
      u = parent[k][u];
      v = parent[k][v];
    }
  }
  return parent[0][u];
}

struct edge {
  int to, cost;
};
vector<edge> wG[MAX_V];

int wd[MAX_V];

void calc_dist(int x, int par) {
  for (const auto &e : wG[x])
    if (e.to != par) {
      wd[e.to] = wd[x] + e.cost;
      calc_dist(e.to, x);
    }
}

int D(int u, int v) {
  int l = lca(u, v);
  return depth[u] + depth[v] - 2 * depth[l];
}

int WD(int u, int v) {
  int l = lca(u, v);
  return wd[u] + wd[v] - 2 * wd[l];
}

const int INF = 1e9 + 1;
// check u-v path
int f(int u, int v, int t) {
  int LCA = lca(u, v);
  if (LCA == u)
    swap(u, v);

  auto g = [&](int x) {
    int c = u, s = x;
    if (D(u, LCA) < x) {
      c = v;
      s = D(u, v) - x;
    }

    for (int i = MAX_LOG_V - 1; i >= 0; --i)
      if (s >> i & 1)
        c = parent[i][c];
    return max({WD(c, u), WD(c, v), WD(c, t)});
  };

  int l = 0, r = D(u, v);
  while (r - l > 2) {
    int m1 = (l + r) / 2;
    int m2 = m1 + 1;
    if (g(m1) >= g(m2))
      l = m1;
    else
      r = m2;
  }

  int ret = INF;
  for (int i = l; i <= r; ++i)
    ret = min(ret, g(i));
  return ret;
}

int main() {
  int n, q;
  scanf(" %d %d", &n, &q);
  rep(i, n - 1) {
    int u, v, w;
    scanf(" %d %d %d", &u, &v, &w);
    --u;
    --v;

    G[u].pb(v);
    G[v].pb(u);
    wG[u].pb({v, w});
    wG[v].pb({u, w});
  }

  lca_init(n);

  wd[root] = 0;
  calc_dist(root, -1);

  rep(i, q) {
    int a, b, c;
    scanf(" %d %d %d", &a, &b, &c);
    --a;
    --b;
    --c;

    int ans = min(f(a, b, c), f(a, c, b));
    printf("%d\\n", ans);
  }
  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, n) for (int(i) = 0; (i) < (int)(n); ++(i))
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout << #x " = " << ((x)) << endl
template <class T, class U>
ostream &operator<<(ostream &o, const pair<T, U> &p) {
  o << "(" << p.fi << "," << p.se << ")";
  return o;
}
template <class T> ostream &operator<<(ostream &o, const vector<T> &v) {
  o << "[";
  for (T t : v) {
    o << t << ",";
  }
  o << "]";
  return o;
}

// ノードの個数
const int MAX_V = 100000;
// ダブリングに必要なサイズ(log(MAX_V))
const int MAX_LOG_V = 17;
// 木の隣接リスト表現
vector<int> G[MAX_V];
// 根のノード番号
int root = 0;

// 親を2^k回辿って到達するノード(根を通り過ぎる場合,-1)
int parent[MAX_LOG_V][MAX_V];
// 根からの深さ
int depth[MAX_V];

// 現在vに注目、親はp、深さd
void lca_dfs(int v, int p, int d) {
  parent[0][v] = p;
  depth[v] = d;
  rep(i, G[v].size()) {
    if (G[v][i] != p) { // 親でなければ子
      lca_dfs(G[v][i], v, d + 1);
    }
  }
}

// 初期化
void lca_init(int V) {
  // parent[0]とdepthの初期化
  lca_dfs(root, -1, 0);
  // parentの初期化
  for (int k = 0; k + 1 < MAX_LOG_V; ++k) {
    for (int v = 0; v < V; ++v) {
      if (parent[k][v] < 0)
        parent[k + 1][v] = -1;
      else
        parent[k + 1][v] = parent[k][parent[k][v]];
    }
  }
}

// uとvのLCAを求める
int lca(int u, int v) {
  // uとvの深さが同じになるまで親を辿る
  if (depth[u] > depth[v])
    swap(u, v);
  for (int k = 0; k < MAX_LOG_V; ++k) {
    if ((depth[v] - depth[u]) >> k & 1)
      v = parent[k][v];
  }
  if (u == v)
    return u;
  // 二分探索でLCAを求める
  for (int k = MAX_LOG_V - 1; k >= 0; --k) {
    if (parent[k][u] != parent[k][v]) {
      u = parent[k][u];
      v = parent[k][v];
    }
  }
  return parent[0][u];
}

struct edge {
  int to, cost;
};
vector<edge> wG[MAX_V];

int wd[MAX_V];

void calc_dist(int x, int par) {
  for (const auto &e : wG[x])
    if (e.to != par) {
      wd[e.to] = wd[x] + e.cost;
      calc_dist(e.to, x);
    }
}

inline int D(int u, int v) {
  int l = lca(u, v);
  return depth[u] + depth[v] - 2 * depth[l];
}

inline int WD(int u, int v) {
  int l = lca(u, v);
  return wd[u] + wd[v] - 2 * wd[l];
}

const int INF = 1e9 + 1;
// check u-v path
int f(int u, int v, int t) {
  int LCA = lca(u, v);
  if (LCA == u)
    swap(u, v);

  auto g = [&](int x) {
    int c = u, s = x;
    if (D(u, LCA) < x) {
      c = v;
      s = D(u, v) - x;
    }

    for (int i = MAX_LOG_V - 1; i >= 0; --i)
      if (s >> i & 1)
        c = parent[i][c];
    return max({WD(c, u), WD(c, v), WD(c, t)});
  };

  int l = 0, r = D(u, v);
  while (r - l > 2) {
    int m1 = (l + r) / 2;
    int m2 = m1 + 1;
    if (g(m1) >= g(m2))
      l = m1;
    else
      r = m2;
  }

  int ret = INF;
  for (int i = l; i <= r; ++i)
    ret = min(ret, g(i));
  return ret;
}

int main() {
  int n, q;
  scanf(" %d %d", &n, &q);
  rep(i, n - 1) {
    int u, v, w;
    scanf(" %d %d %d", &u, &v, &w);
    --u;
    --v;

    G[u].pb(v);
    G[v].pb(u);
    wG[u].pb({v, w});
    wG[v].pb({u, w});
  }

  lca_init(n);

  wd[root] = 0;
  calc_dist(root, -1);

  rep(i, q) {
    int a, b, c;
    scanf(" %d %d %d", &a, &b, &c);
    --a;
    --b;
    --c;

    int ans = min({f(a, b, c), f(b, c, a), f(c, a, b)});
    printf("%d\\n", ans);
  }
  return 0;
}