Problem p02698 (C++) — buggy submission, verdict: Runtime Error

// 木の上で最長増加部分列 (LIS: Longest Increasing Subsequence)するだけ

#include <algorithm>
#include <array>
#include <bitset>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
using namespace std;
#define int long long
using P = pair<int, int>;
constexpr int INF = 1000000000 + 8;

class Graph {
private:
  struct edge {
    int to;
    edge(int i) : to(i) {}
  };
  vector<vector<edge>> edges;
  vector<int> numbers, answers, lis;

public:
  Graph(int n) {
    edges.resize(n);
    numbers.resize(n);
    answers.resize(n);
    lis.assign(n, INF);
  };
  int size() const { return edges.size(); };
  void addDirectedEdge(int from, int to) { edges[from].push_back(edge(to)); }
  void addEdge(int from, int to) {
    addDirectedEdge(from, to);
    addDirectedEdge(to, from);
  }
  void writeNumber(int i, int num) { numbers[i] = num; }

  // p: 今の点の番号, pp: 移動前の点の番号, np: 移動後の点の番号
  void dfs(int p = 0, int pp = -1) {
    // LISのDP配列に今いる点の番号の情報を追加
    // 子を探索したあとにLISのDP配列をもとに戻すため、変更した要素の値とイテレータを記録
    const auto itr_updated_element =
        lower_bound(lis.begin(), lis.end(), numbers[p]);
    const int old_val_updated_element = *itr_updated_element;
    *itr_updated_element = numbers[p];

    answers[p] = lower_bound(lis.begin(), lis.end(), INF) - lis.begin();

    // 子を探索
    for (auto &&edge : edges[p]) {
      const int np = edge.to;
      if (np == pp)
        continue;
      dfs(np, p);
    }

    // LISのDP配列を元に戻す
    *itr_updated_element = old_val_updated_element;
  }
  int answer(int p) const { return answers[p]; }
};

signed main() {
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n;
  cin >> n;
  Graph g(n);

  for (int i = 0; i < n; i++) {
    int a;
    cin >> a;
    g.writeNumber(i, a);
  }

  for (int i = 0; i < n - 1; i++) {
    int u, v;
    cin >> u >> v;
    u--, v--;

    g.addEdge(u, v);
  }

  g.dfs();
  for (int i = 0; i < n; i++) {
    cout << g.answer(i) << endl;
  }
}


Error: 0

Fixed submission:

// 木の上で最長増加部分列 (LIS: Longest Increasing Subsequence)するだけ

#include <algorithm>
#include <array>
#include <bitset>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>
using namespace std;
#define int long long
using P = pair<int, int>;
constexpr int INF = 1000000000 + 8;

class Graph {
private:
  struct edge {
    int to;
    edge(int i, int c = 1) : to(i) {}
  };
  vector<vector<edge>> edges;
  vector<int> numbers, answers, lis;

public:
  Graph(int n) {
    edges.resize(n);
    numbers.resize(n);
    answers.resize(n);
    lis.assign(n, INF);
  };
  int size() const { return edges.size(); };
  void addDirectedEdge(int from, int to) { edges[from].push_back(edge(to)); }
  void addEdge(int from, int to) {
    addDirectedEdge(from, to);
    addDirectedEdge(to, from);
  }
  void writeNumber(int i, int num) { numbers[i] = num; }

  // p: 今の点の番号, pp: 移動前の点の番号, np: 移動後の点の番号
  void dfs(int p = 0, int pp = -1) {
    // LISのDP配列に今いる点の番号の情報を追加
    // 子を探索したあとにLISのDP配列をもとに戻すため、変更した要素の値とイテレータを記録
    const auto itr_updated_element =
        lower_bound(lis.begin(), lis.end(), numbers[p]);
    const int old_val_updated_element = *itr_updated_element;
    *itr_updated_element = numbers[p];

    answers[p] = lower_bound(lis.begin(), lis.end(), INF) - lis.begin();

    // 子を探索
    for (auto &&edge : edges[p]) {
      const int np = edge.to;
      if (np == pp)
        continue;
      dfs(np, p);
    }

    // LISのDP配列を元に戻す
    *itr_updated_element = old_val_updated_element;
  }
  int answer(int p) const { return answers[p]; }
};

signed main() {
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n;
  cin >> n;
  Graph g(n);

  for (int i = 0; i < n; i++) {
    int a;
    cin >> a;
    g.writeNumber(i, a);
  }

  for (int i = 0; i < n; i++) {
    int u, v;
    cin >> u >> v;
    u--, v--;

    g.addEdge(u, v);
  }

  g.dfs();
  for (int i = 0; i < n; i++) {
    cout << g.answer(i) << endl;
  }
}