제출 #1296221

#제출 시각아이디문제언어결과실행 시간메모리
1296221avighnaCat in a tree (BOI17_catinatree)C++20
51 / 100
372 ms589824 KiB
#include <bits/stdc++.h>

namespace algo {
template <typename T>
class segment_tree {
private:
  std::size_t n;
  std::vector<T> seg;

  struct accessor {
    segment_tree &st;
    std::size_t i;
    accessor(segment_tree &st, std::size_t i) : st(st), i(i) {}
    accessor &operator=(const T &x) {
      st.set(i, x);
      return *this;
    }
    accessor &operator+=(const T &x) { return *this = st.at(i) + x; }
    accessor &operator-=(const T &x) { return *this = st.at(i) - x; }
    operator T() const { return st.at(i); }
    friend std::ostream &operator<<(std::ostream &os, const accessor &acc) {
      return os << T(acc);
    }
  };

public:
  segment_tree(std::size_t n) : n(n), seg(2 * n) {}
  segment_tree(const segment_tree &other) : n(other.n), seg(other.seg) {}
  segment_tree() : n(0) {}
  segment_tree(std::size_t n, const T &x) : n(n), seg(2 * n) {
    for (std::size_t i = n; i < 2 * n; ++i) {
      seg[i] = x;
    }
    for (std::size_t i = n - 1; i > 0; --i) {
      seg[i] = seg[2 * i] + seg[2 * i + 1];
    }
  }
  segment_tree(const std::vector<T> &vals) : n(vals.size()), seg(2 * n) {
    set(vals);
  }
  void set(std::size_t i, const T &x) {
    for (seg[i += n] = x, i /= 2; i > 0; i /= 2) {
      seg[i] = seg[2 * i] + seg[2 * i + 1];
    }
  }
  T query(std::size_t l, std::size_t r) const {
    T ans_l = T{}, ans_r = T{};
    for (l += n, r += n + 1; l < r; l /= 2, r /= 2) {
      if (l & 1)
        ans_l = ans_l + seg[l++];
      if (r & 1)
        ans_r = seg[--r] + ans_r;
    }
    return ans_l + ans_r;
  }
  std::size_t size() const { return n; }
  const T &at(std::size_t i) const { return seg[n + i]; }
  accessor operator[](std::size_t i) { return accessor(*this, i); }
};
template <typename T>
  requires std::is_arithmetic_v<T>
struct max_t {
  T x;
  constexpr max_t() : x(std::numeric_limits<T>::min()) {}
  constexpr max_t(const T &x) : x(x) {}
  constexpr max_t operator+(const max_t &other) const {
    return std::max(x, other.x);
  }
  constexpr operator T() const { return x; }
  constexpr bool operator==(const max_t &other) const { return x == other.x; }
  constexpr bool operator!=(const max_t &other) const { return x != other.x; }
};
} // namespace algo

using namespace std;
using namespace algo;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n, d;
  cin >> n >> d;
  vector<vector<int>> adj(n);
  for (int i = 1, p; i < n; ++i) {
    cin >> p;
    adj[p].push_back(i);
  }

  if (d >= n) {
    cout << "1\n";
    return 0;
  }

  vector<int> sz(n);
  auto dfs_sz = [&](auto &&self, int u) -> void {
    sz[u] = 1;
    for (int &i : adj[u]) {
      self(self, i);
      sz[u] += sz[i];
    }
  };
  dfs_sz(dfs_sz, 0);

  auto dfs = [&](auto &&self, int u) -> segment_tree<max_t<int>> {
    segment_tree<max_t<int>> dp(sz[u], 0);
    for (int &i : adj[u]) {
      segment_tree<max_t<int>> _ndp = self(self, i);
      segment_tree<max_t<int>> ndp(_ndp.size() + 1, 0);
      for (int i = 1; i <= _ndp.size(); ++i) {
        ndp[i] = int{_ndp.at(i - 1)};
      }

      if (ndp.size() > dp.size()) {
        swap(dp, ndp);
      }

      vector<int> qvals;
      for (int i = 0; i < ndp.size(); ++i) {
        if (max(i + 1, d - i) < dp.size()) {
          qvals.push_back(dp.query(max(i + 1, d - i), dp.size() - 1));
        } else {
          qvals.push_back(0);
        }
      }

      for (int i = 0; i < ndp.size(); ++i) {
        if (max(i, d - i) < ndp.size()) {
          dp[i] = int{dp.at(i)} + int{ndp.query(max(i, d - i), ndp.size() - 1)};
        }
      }
      for (int i = 0; i < ndp.size(); ++i) {
        dp[i] = max(int{dp.at(i)}, int{ndp.at(i)});
      }
      for (int i = 0; i < ndp.size(); ++i) {
        if (max(i + 1, d - i) < dp.size()) {
          dp[i] = max(int{dp.at(i)}, qvals[i] + int{ndp.at(i)});
        }
      }
    }
    dp[0] = max(int{dp.at(0)}, (d < sz[u] ? int{dp.at(d)} : 0) + 1);
    return dp;
  };

  segment_tree<max_t<int>> dp = dfs(dfs, 0);
  cout << dp.query(0, dp.size() - 1) << '\n';
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...