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

#include <bits/stdc++.h>
using namespace std;

template <typename T> class Graph {
  void _dfs_toporogical_sort(vector<bool> &visited, const int n,
                             list<long long> &ret) const {
    if (visited[n]) {
      return;
    }
    visited[n] = true;
    for (auto e : this->edge[n]) {
      _dfs_toporogical_sort(visited, e.to, ret);
    }
    ret.push_front(n);
  }

  void set_node(const long long N) { this->node = N + 1; }

public:
  struct Edge {
    long long to;
    T distance;
    Edge(const long long t, const T d) {
      this->to = t;
      this->distance = d;
    }
    bool operator<(const Graph<T>::Edge &e) const {
      return this->distance < e.distance;
    }
    bool operator<=(const Graph<T>::Edge &e) const {
      return this->distance <= e.distance;
    }
    bool operator>(const Graph<T>::Edge &e) const {
      return this->distance > e.distance;
    }
    bool operator>=(const Graph<T>::Edge &e) const {
      return this->distance >= e.distance;
    }
    bool operator==(const Graph<T>::Edge &e) const {
      return this->distance == e.distance;
    }
  };
  class UnionFind {
  public:
    vector<long long> root;

    UnionFind(const long long N) { this->root = vector<long long>(N + 1, -1); }

    long long find_root(const long long A) {
      if (this->root[A] < 0) {
        return A;
      } else {
        this->root[A] = find_root(this->root[A]);
      }
      return this->root[A];
    }

    long long size(const long long A) { return -this->root[find_root(A)]; }

    bool unite(long long A, long long B) {
      A = find_root(A);
      B = find_root(B);
      if (A == B) {
        return false;
      }

      if (size(A) < size(B)) {
        swap(A, B);
      }

      this->root[A] += this->root[B];
      this->root[B] = A;

      return true;
    }

    bool has_same_root(const long long A, const long long B) {
      return find_root(A) == find_root(B);
    }
  };
  vector<vector<T>> adjacency_matrix;
  long long node;
  T initial_value;
  vector<vector<Graph<T>::Edge>> edge;

  Graph(const long long N) {
    this->set_node(N);
    this->initialize_edge_vector();
  }

  Graph(const long long N, const T init) {
    this->set_node(N);
    this->initialize_edge_vector();
    this->set_initial_value(init);
  }

  void set_initial_value(const T init) { this->initial_value = init; }

  void initialize_adjacency_matrix() {
    this->adjacency_matrix = vector<vector<T>>(
        this->node, vector<T>(this->node, this->initial_value));
  }

  void initialize_adjacency_matrix(const T init) {
    this->set_initial_value(init);
    this->initialize_adjacency_matrix();
  }

  void initialize_edge_vector() {
    this->edge = vector<vector<Graph<T>::Edge>>(this->node);
  }

  void update_adjacency_matrix(const long long from, const long long to,
                               const T distance = 1) {
    this->adjacency_matrix[from][to] = distance;
  }

  void add_edge(const long long from, const long long to,
                const T distance = 1) {
    this->edge[from].push_back({to, distance});
  }

  // O(V^3)
  // CAUTION: Use adjacency matrix
  vector<vector<T>> run_floyd_warshall() const {
    vector<vector<T>> ret(this->adjacency_matrix);
    for (long long i = 0; i < this->node; i++) {
      for (long long j = 0; j < this->node; j++) {
        for (long long k = 0; k < this->node; k++) {
          ret[j][k] = min(ret[j][k], ret[j][i] + ret[i][k]);
        }
      }
    }
    return ret;
  }

  // O(E)
  // CAUTION: Non-weighted only
  // CAUTION: Use edge vector
  vector<T> run_bfs(const long long from) const {
    vector<T> distance(this->node, this->initial_value);
    vector<bool> visited(this->node, false);
    queue<long long> q;
    q.push(from);
    for (long long i = 0; i < this->node && !q.empty(); i++) {
      queue<long long> tmp;
      while (!q.empty()) {
        if (visited[q.front()]) {
          q.pop();
          continue;
        }
        distance[q.front()] = i;
        visited[q.front()] = true;
        for (Graph<T>::Edge e : this->edge[q.front()]) {
          if (visited[e.to]) {
            continue;
          }
          tmp.push(e.to);
        }
        q.pop();
      }
      q = tmp;
    }
    return distance;
  }

  // O(VE)
  // CAUTION: Use edge vector
  vector<T> run_bellman_ford(const long long from) const {
    vector<T> distance(this->node, this->initial_value);
    distance[from] = 0;

    for (long long i = 0; i < this->node - 1; i++) {
      for (long long j = 0; j < this->node; j++) {
        for (Graph<T>::Edge e : this->edge[j]) {
          if (distance[e.to] > distance[j] + e.distance) {
            distance[e.to] = distance[j] + e.distance;
          }
        }
      }
    }
    return distance;
  }

  // O(E + VlogV)
  // CAUTION: Use edge vector
  // CAUTION: Node-indices must be [1, N]
  vector<T> run_dijkstra(const long long from) const {
    vector<T> distance(this->node, this->initial_value);
    priority_queue<Graph<T>::Edge, vector<Graph<T>::Edge>,
                   greater<Graph<T>::Edge>>
        queue;
    queue.push(Graph<T>::Edge(from, 0));
    for (long long i = 1; i < this->node && !queue.empty(); i++) {
      T d = queue.top().distance;
      long long to = queue.top().to;
      queue.pop();
      if (distance[to] == this->initial_value) {
        distance[to] = d;
        for (Graph<T>::Edge e : this->edge[to]) {
          if (distance[e.to] == this->initial_value) {
            queue.push({e.to, e.distance + d});
          }
        }
      } else {
        i--;
      }
    }
    return distance;
  }

  // O(ElogV)
  // CAUTION: Use edge vector
  // CAUTION: Node-indices must be [1, N]
  T run_prim() const {
    vector<bool> is_visited(this->node, false);
    T cost = 0;
    priority_queue<Graph<T>::Edge, vector<Graph<T>::Edge>,
                   greater<Graph<T>::Edge>>
        queue;
    queue.push(Graph<T>::Edge(1, 0));
    for (long long i = 1; i < this->node && !queue.empty(); i++) {
      T distance = queue.top().distance;
      long long to = queue.top().to;
      queue.pop();
      if (is_visited[to]) {
        i--;
      } else {
        cost += distance;
        is_visited[to] = true;
        for (Graph<T>::Edge e : this->edge[to]) {
          queue.push({e.to, e.distance});
        }
      }
    }
    return cost;
  }

  // O(ElogV)
  // CAUTION: Use edge vector
  T run_kruskal() const {
    T cost = 0;
    vector<pair<Graph<T>::Edge, long long>> edge_from;
    for (long long i = 0; i < this->node; i++) {
      for (auto e : this->edge[i]) {
        edge_from.push_back(make_pair(e, i));
      }
    }
    sort(edge_from.begin(), edge_from.end());

    Graph<T>::UnionFind uf(this->node);
    for (pair<Graph<T>::Edge, long long> e_f : edge_from) {
      auto e = e_f.first;
      long long from = e_f.second;
      if (!uf.has_same_root(from, e.to)) {
        uf.unite(from, e.to);
        cost += e.distance;
      }
    }
    return cost;
  }

  // O(V)
  // CAUTION: Without cycle only
  // CAUTION: Use edge vector
  vector<long long> run_toporogical_sort() const {
    list<long long> ret_list;
    vector<bool> visited(this->node, false);
    for (long long i = 0; i < this->node; i++) {
      _dfs_toporogical_sort(visited, i, ret_list);
    }

    vector<long long> ret(ret_list.begin(), ret_list.end());
    return ret;
  }
};

void dfs(Graph<int> &g, vector<int> &ans, vector<int> &dp, vector<int> &a,
         int prev, int next) {
  auto itr = lower_bound(dp.begin(), dp.end(), a[next]);
  int tmp = *itr;
  *itr = a[next];
  ans[next] = max(ans[prev], int(itr - dp.begin()));
  for (auto e : g.edge[next]) {
    if (e.to == prev) {
      continue;
    }
    dfs(g, ans, dp, a, next, e.to);
  }
  *itr = tmp;
}

int main() {
  int N;
  cin >> N;
  Graph<int> g(N);
  vector<int> a(g.node, 0);
  for (int i = 1; i < g.node; i++) {
    cin >> a[i];
  }
  int u, v;
  for (int i = 0; i < N - 1; i++) {
    cin >> u >> v;
    g.add_edge(u, v);
    g.add_edge(v, u);
  }

  constexpr int MAXIMUM = 1e9 + 5;
  vector<int> ans(g.node, 0);
  vector<int> dp(g.node, MAXIMUM);

  dfs(g, ans, dp, a, 0, 1);

  for (int i = 1; i <= N; i++) {
    cout << ans[i] + 1 << endl;
  }
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;

template <typename T> class Graph {
  void _dfs_toporogical_sort(vector<bool> &visited, const int n,
                             list<long long> &ret) const {
    if (visited[n]) {
      return;
    }
    visited[n] = true;
    for (auto e : this->edge[n]) {
      _dfs_toporogical_sort(visited, e.to, ret);
    }
    ret.push_front(n);
  }

  void set_node(const long long N) { this->node = N + 1; }

public:
  struct Edge {
    long long to;
    T distance;
    Edge(const long long t, const T d) {
      this->to = t;
      this->distance = d;
    }
    bool operator<(const Graph<T>::Edge &e) const {
      return this->distance < e.distance;
    }
    bool operator<=(const Graph<T>::Edge &e) const {
      return this->distance <= e.distance;
    }
    bool operator>(const Graph<T>::Edge &e) const {
      return this->distance > e.distance;
    }
    bool operator>=(const Graph<T>::Edge &e) const {
      return this->distance >= e.distance;
    }
    bool operator==(const Graph<T>::Edge &e) const {
      return this->distance == e.distance;
    }
  };
  class UnionFind {
  public:
    vector<long long> root;

    UnionFind(const long long N) { this->root = vector<long long>(N + 1, -1); }

    long long find_root(const long long A) {
      if (this->root[A] < 0) {
        return A;
      } else {
        this->root[A] = find_root(this->root[A]);
      }
      return this->root[A];
    }

    long long size(const long long A) { return -this->root[find_root(A)]; }

    bool unite(long long A, long long B) {
      A = find_root(A);
      B = find_root(B);
      if (A == B) {
        return false;
      }

      if (size(A) < size(B)) {
        swap(A, B);
      }

      this->root[A] += this->root[B];
      this->root[B] = A;

      return true;
    }

    bool has_same_root(const long long A, const long long B) {
      return find_root(A) == find_root(B);
    }
  };
  vector<vector<T>> adjacency_matrix;
  long long node;
  T initial_value;
  vector<vector<Graph<T>::Edge>> edge;

  Graph(const long long N) {
    this->set_node(N);
    this->initialize_edge_vector();
  }

  Graph(const long long N, const T init) {
    this->set_node(N);
    this->initialize_edge_vector();
    this->set_initial_value(init);
  }

  void set_initial_value(const T init) { this->initial_value = init; }

  void initialize_adjacency_matrix() {
    this->adjacency_matrix = vector<vector<T>>(
        this->node, vector<T>(this->node, this->initial_value));
  }

  void initialize_adjacency_matrix(const T init) {
    this->set_initial_value(init);
    this->initialize_adjacency_matrix();
  }

  void initialize_edge_vector() {
    this->edge = vector<vector<Graph<T>::Edge>>(this->node);
  }

  void update_adjacency_matrix(const long long from, const long long to,
                               const T distance = 1) {
    this->adjacency_matrix[from][to] = distance;
  }

  void add_edge(const long long from, const long long to,
                const T distance = 1) {
    this->edge[from].push_back({to, distance});
  }

  // O(V^3)
  // CAUTION: Use adjacency matrix
  vector<vector<T>> run_floyd_warshall() const {
    vector<vector<T>> ret(this->adjacency_matrix);
    for (long long i = 0; i < this->node; i++) {
      for (long long j = 0; j < this->node; j++) {
        for (long long k = 0; k < this->node; k++) {
          ret[j][k] = min(ret[j][k], ret[j][i] + ret[i][k]);
        }
      }
    }
    return ret;
  }

  // O(E)
  // CAUTION: Non-weighted only
  // CAUTION: Use edge vector
  vector<T> run_bfs(const long long from) const {
    vector<T> distance(this->node, this->initial_value);
    vector<bool> visited(this->node, false);
    queue<long long> q;
    q.push(from);
    for (long long i = 0; i < this->node && !q.empty(); i++) {
      queue<long long> tmp;
      while (!q.empty()) {
        if (visited[q.front()]) {
          q.pop();
          continue;
        }
        distance[q.front()] = i;
        visited[q.front()] = true;
        for (Graph<T>::Edge e : this->edge[q.front()]) {
          if (visited[e.to]) {
            continue;
          }
          tmp.push(e.to);
        }
        q.pop();
      }
      q = tmp;
    }
    return distance;
  }

  // O(VE)
  // CAUTION: Use edge vector
  vector<T> run_bellman_ford(const long long from) const {
    vector<T> distance(this->node, this->initial_value);
    distance[from] = 0;

    for (long long i = 0; i < this->node - 1; i++) {
      for (long long j = 0; j < this->node; j++) {
        for (Graph<T>::Edge e : this->edge[j]) {
          if (distance[e.to] > distance[j] + e.distance) {
            distance[e.to] = distance[j] + e.distance;
          }
        }
      }
    }
    return distance;
  }

  // O(E + VlogV)
  // CAUTION: Use edge vector
  // CAUTION: Node-indices must be [1, N]
  vector<T> run_dijkstra(const long long from) const {
    vector<T> distance(this->node, this->initial_value);
    priority_queue<Graph<T>::Edge, vector<Graph<T>::Edge>,
                   greater<Graph<T>::Edge>>
        queue;
    queue.push(Graph<T>::Edge(from, 0));
    for (long long i = 1; i < this->node && !queue.empty(); i++) {
      T d = queue.top().distance;
      long long to = queue.top().to;
      queue.pop();
      if (distance[to] == this->initial_value) {
        distance[to] = d;
        for (Graph<T>::Edge e : this->edge[to]) {
          if (distance[e.to] == this->initial_value) {
            queue.push({e.to, e.distance + d});
          }
        }
      } else {
        i--;
      }
    }
    return distance;
  }

  // O(ElogV)
  // CAUTION: Use edge vector
  // CAUTION: Node-indices must be [1, N]
  T run_prim() const {
    vector<bool> is_visited(this->node, false);
    T cost = 0;
    priority_queue<Graph<T>::Edge, vector<Graph<T>::Edge>,
                   greater<Graph<T>::Edge>>
        queue;
    queue.push(Graph<T>::Edge(1, 0));
    for (long long i = 1; i < this->node && !queue.empty(); i++) {
      T distance = queue.top().distance;
      long long to = queue.top().to;
      queue.pop();
      if (is_visited[to]) {
        i--;
      } else {
        cost += distance;
        is_visited[to] = true;
        for (Graph<T>::Edge e : this->edge[to]) {
          queue.push({e.to, e.distance});
        }
      }
    }
    return cost;
  }

  // O(ElogV)
  // CAUTION: Use edge vector
  T run_kruskal() const {
    T cost = 0;
    vector<pair<Graph<T>::Edge, long long>> edge_from;
    for (long long i = 0; i < this->node; i++) {
      for (auto e : this->edge[i]) {
        edge_from.push_back(make_pair(e, i));
      }
    }
    sort(edge_from.begin(), edge_from.end());

    Graph<T>::UnionFind uf(this->node);
    for (pair<Graph<T>::Edge, long long> e_f : edge_from) {
      auto e = e_f.first;
      long long from = e_f.second;
      if (!uf.has_same_root(from, e.to)) {
        uf.unite(from, e.to);
        cost += e.distance;
      }
    }
    return cost;
  }

  // O(V)
  // CAUTION: Without cycle only
  // CAUTION: Use edge vector
  vector<long long> run_toporogical_sort() const {
    list<long long> ret_list;
    vector<bool> visited(this->node, false);
    for (long long i = 0; i < this->node; i++) {
      _dfs_toporogical_sort(visited, i, ret_list);
    }

    vector<long long> ret(ret_list.begin(), ret_list.end());
    return ret;
  }
};

void dfs(Graph<int> &g, vector<int> &ans, vector<int> &dp, vector<int> &a,
         int prev, int next) {
  auto itr = lower_bound(dp.begin(), dp.end(), a[next]);
  *itr = a[next];
  ans[next] = max(ans[prev], int(itr - dp.begin()));
  if (dp.back() != (int)(1e9 + 5)) {
    dp.push_back(1e9 + 5);
  }
  for (auto e : g.edge[next]) {
    if (e.to == prev) {
      continue;
    }
    if (next != 1 && g.edge[next].size() == 2) {
      dfs(g, ans, dp, a, next, e.to);
    } else {
      vector<int> tmp = dp;
      dfs(g, ans, tmp, a, next, e.to);
    }
  }
}

int main() {
  int N;
  cin >> N;
  Graph<int> g(N);
  vector<int> a(g.node, 0);
  for (int i = 1; i < g.node; i++) {
    cin >> a[i];
  }
  int u, v;
  for (int i = 0; i < N - 1; i++) {
    cin >> u >> v;
    g.add_edge(u, v);
    g.add_edge(v, u);
  }

  vector<int> ans(g.node, 0);
  vector<int> dp(1, 0);
  constexpr int MAXIMUM = 1e9 + 5;
  dp.push_back(MAXIMUM);

  dfs(g, ans, dp, a, 0, 1);

  // for (int i = 0; i < N; i++)
  // {
  //     int next = q.front().first;
  //     int prev = q.front().second;
  //     q.pop();
  //     dp[next] = dp[prev];
  //     auto itr = lower_bound(dp[next].begin(), dp[next].end(), a[next]);
  //     *itr = a[next];
  //     ans[next] = max(ans[prev], int(itr - dp[next].begin()));
  //     dp[next].push_back(MAXIMUM);
  //     for (auto e : g.edge[next])
  //     {
  //         if (e.to == prev)
  //         {
  //             continue;
  //         }
  //         q.push(make_pair(e.to, next));
  //     }
  // }
  for (int i = 1; i <= N; i++) {
    cout << ans[i] << endl;
  }
}