Problem p02373 (C++) — buggy submission, verdict: Memory Limit Exceeded

#include <cmath>
#include <iostream>
#include <vector>

using namespace std;
constexpr int MAX_LOG_V = 50;
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

struct Edge {
  int to, weight;
  Edge(int t, int w) : to(t), weight(w) {}
};

using Edges = vector<Edge>;
using Graph = vector<Edges>;

class Tree {
public:
  Tree(int size) : mGraph(size), mMemo(size) {}
  void add_edge(int s, int t, int w = 1) {
    mGraph[s].emplace_back(t, w);
    mGraph[t].emplace_back(s, w);
  }

  // diameter of a tree
  pair<int, int> dfs(int v, int pv) {
    pair<int, int> ret(0, v);
    for (Edge nv : mGraph[v]) {
      if (nv.to == pv)
        continue;
      pair<int, int> tmp = dfs(nv.to, v);
      if (chmax(ret.first, tmp.first + nv.weight)) {
        ret.second = tmp.second;
      }
    }
    return ret;
  }

  int diameter() {
    pair<int, int> s = dfs(0, -1);
    pair<int, int> t = dfs(s.second, -1);
    return t.first;
  }
  //

  // height of a tree
  int dfs_memo(int v, int e) {
    if (mMemo[v][e].weight >= 0)
      return mMemo[v][e].weight;
    mMemo[v][e].weight = mGraph[v][e].weight;
    int nv = mMemo[v][e].to;
    for (int ne = 0; ne < mMemo[nv].size(); ++ne) {
      if (mMemo[nv][ne].to == v)
        continue;
      mMemo[v][e].weight =
          max(mMemo[v][e].weight, dfs_memo(nv, ne) + mGraph[v][e].weight);
    }
    return mMemo[v][e].weight;
  }

  vector<int> height() {
    mMemo = mGraph;
    // init memo
    for (int i = 0; i < mMemo.size(); ++i) {
      for (int j = 0; j < mMemo[i].size(); ++j) {
        mMemo[i][j].weight = -1;
      }
    }
    //
    for (int i = 0; i < mMemo.size(); ++i) {
      for (int j = 0; j < mMemo[i].size(); ++j) {
        if (mMemo[i][j].weight < 0) {
          mMemo[i][j].weight = dfs_memo(i, j);
        }
      }
    }

    // calc result
    vector<int> ret(mMemo.size());
    for (int i = 0; i < mMemo.size(); ++i) {
      for (int j = 0; j < mMemo[i].size(); ++j) {
        ret[i] = max(ret[i], mMemo[i][j].weight);
      }
    }
    return ret;
  }
  //

  // Lowest Common Ancester
  void SetParentAndDepth(int v, int pv, int d) {
    mPar[0][v] = pv; // v is pv's 2^0 parent
    mDepth[v] = d;
    for (auto nv : mGraph[v]) {
      if (nv.to == pv)
        continue;
      SetParentAndDepth(nv.to, v, d + 1);
    }
  }

  void Init(int root) {
    mPar.resize(MAX_LOG_V, vector<int>(mGraph.size()));
    mDepth.resize(mGraph.size());
    SetParentAndDepth(root, -1, 0);
    // calc 2^k parent of each vert
    for (int k = 0; k + 1 < MAX_LOG_V; ++k) {
      for (int v = 0; v < mGraph.size(); ++v) {
        if (mPar[k][v] < 0)
          mPar[k + 1][v] = -1; // not having parent
        else
          mPar[k + 1][v] = mPar[k][mPar[k][v]];
      }
    }
  }

  int GetLca(int u, int v) {
    while (mDepth[u] > mDepth[v])
      swap(u, v);
    for (int k = 0; k < MAX_LOG_V; ++k) {
      if ((mDepth[v] - mDepth[u]) >> k & 1) {
        v = mPar[k][v];
      }
    }
    if (u == v)
      return u;
    for (int k = MAX_LOG_V - 1; k >= 0; --k) {
      if (mPar[k][u] != mPar[k][v]) {
        u = mPar[k][u];
        v = mPar[k][v];
      }
    }
    return mPar[0][u];
  }
  //

private:
  Graph mGraph;
  Graph mMemo;

  // LCA
  vector<vector<int>> mPar;
  vector<int> mDepth;
};

int main() {
  int n, q, k, x, y;
  cin >> n;
  Tree tree(n);
  for (int i = 0; i < n; ++i) {
    cin >> k;
    for (int j = 0; j < k; ++j) {
      cin >> x;
      tree.add_edge(i, x);
    }
  }
  tree.Init(0);
  cin >> q;
  for (int i = 0; i < q; ++i) {
    cin >> x >> y;
    cout << tree.GetLca(x, y) << '\\n';
  }
  return 0;
}


Error: MLE

Fixed submission:

#include <cmath>
#include <iostream>
#include <vector>

using namespace std;
template <class T> inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}

struct Edge {
  int to, weight;
  Edge(int t, int w) : to(t), weight(w) {}
};

using Edges = vector<Edge>;
using Graph = vector<Edges>;

class Tree {
public:
  Tree(int size) : mGraph(size), mMemo(size), mLog2v(log2(size)) {}
  void add_edge(int s, int t, int w = 1) {
    mGraph[s].emplace_back(t, w);
    mGraph[t].emplace_back(s, w);
  }

  // diameter of a tree
  pair<int, int> dfs(int v, int pv) {
    pair<int, int> ret(0, v);
    for (Edge nv : mGraph[v]) {
      if (nv.to == pv)
        continue;
      pair<int, int> tmp = dfs(nv.to, v);
      if (chmax(ret.first, tmp.first + nv.weight)) {
        ret.second = tmp.second;
      }
    }
    return ret;
  }

  int diameter() {
    pair<int, int> s = dfs(0, -1);
    pair<int, int> t = dfs(s.second, -1);
    return t.first;
  }
  //

  // height of a tree
  int dfs_memo(int v, int e) {
    if (mMemo[v][e].weight >= 0)
      return mMemo[v][e].weight;
    mMemo[v][e].weight = mGraph[v][e].weight;
    int nv = mMemo[v][e].to;
    for (int ne = 0; ne < mMemo[nv].size(); ++ne) {
      if (mMemo[nv][ne].to == v)
        continue;
      mMemo[v][e].weight =
          max(mMemo[v][e].weight, dfs_memo(nv, ne) + mGraph[v][e].weight);
    }
    return mMemo[v][e].weight;
  }

  vector<int> height() {
    mMemo = mGraph;
    // init memo
    for (int i = 0; i < mMemo.size(); ++i) {
      for (int j = 0; j < mMemo[i].size(); ++j) {
        mMemo[i][j].weight = -1;
      }
    }
    //
    for (int i = 0; i < mMemo.size(); ++i) {
      for (int j = 0; j < mMemo[i].size(); ++j) {
        if (mMemo[i][j].weight < 0) {
          mMemo[i][j].weight = dfs_memo(i, j);
        }
      }
    }

    // calc result
    vector<int> ret(mMemo.size());
    for (int i = 0; i < mMemo.size(); ++i) {
      for (int j = 0; j < mMemo[i].size(); ++j) {
        ret[i] = max(ret[i], mMemo[i][j].weight);
      }
    }
    return ret;
  }
  //

  // Lowest Common Ancester
  void SetParentAndDepth(int v, int pv, int d) {
    mPar[0][v] = pv; // v is pv's 2^0 parent
    mDepth[v] = d;
    for (auto nv : mGraph[v]) {
      if (nv.to == pv)
        continue;
      SetParentAndDepth(nv.to, v, d + 1);
    }
  }

  void Init(int root) {
    mPar.resize(mGraph.size());
    for (int i = 0; i < mGraph.size(); ++i)
      mPar[i].resize(mGraph.size());
    mDepth.resize(mGraph.size());
    SetParentAndDepth(root, -1, 0);
    // calc 2^k parent of each vert
    for (int k = 0; k + 1 < mLog2v; ++k) {
      for (int v = 0; v < mGraph.size(); ++v) {
        if (mPar[k][v] < 0)
          mPar[k + 1][v] = -1; // not having parent
        else
          mPar[k + 1][v] = mPar[k][mPar[k][v]];
      }
    }
  }

  int GetLca(int u, int v) {
    while (mDepth[u] > mDepth[v])
      swap(u, v);
    for (int k = 0; k < mLog2v; ++k) {
      if ((mDepth[v] - mDepth[u]) >> k & 1) {
        v = mPar[k][v];
      }
    }
    if (u == v)
      return u;
    for (int k = mLog2v - 1; k >= 0; --k) {
      if (mPar[k][u] != mPar[k][v]) {
        u = mPar[k][u];
        v = mPar[k][v];
      }
    }
    return mPar[0][u];
  }
  //

private:
  Graph mGraph;
  Graph mMemo;

  // LCA
  int mLog2v;
  vector<vector<int>> mPar;
  vector<int> mDepth;
};

int main() {
  int n, q, k, x, y;
  cin >> n;
  Tree tree(n);
  for (int i = 0; i < n; ++i) {
    cin >> k;
    for (int j = 0; j < k; ++j) {
      cin >> x;
      tree.add_edge(i, x);
    }
  }
  tree.Init(0);
  cin >> q;
  for (int i = 0; i < q; ++i) {
    cin >> x >> y;
    cout << tree.GetLca(x, y) << '\\n';
  }
  return 0;
}