#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5;
int n;
long long init_money, res;
pair<long long, int> a[maxn];
vector<int> adj[maxn];
// Thay vector bằng multiset
multiset<pair<long long, long long>> ms[maxn];
inline void DFS(int u) {
for (int v : adj[u]) {
DFS(v);
// Kỹ thuật Small-to-Large Merging:
// Nếu tập con lớn hơn tập cha, hoán đổi để luôn insert từ tập nhỏ vào tập lớn
if (ms[v].size() > ms[u].size()) {
swap(ms[u], ms[v]);
}
// Gộp các phần tử từ con vào cha
for (auto &x : ms[v]) {
ms[u].insert(x);
}
ms[v].clear(); // Xóa bộ nhớ tập con sau khi gộp
}
// Nếu là node ảo (gốc 0), ta không xử lý logic gộp lỗ lãi của chính nó
if (u == 0) return;
// Tạo job hiện tại: {cost (số âm), profit}
pair<long long, long long> cur = {min(0LL, a[u].first), a[u].first};
// Logic Greedy:
// Nếu job hiện tại đang lỗ (cur.second <= 0), ta cần "kéo" các job có lãi từ con lên để bù.
// Ta chọn job có cost lớn nhất (ít âm nhất - dễ thực hiện nhất) từ multiset.
// Trong multiset (sort tăng dần theo first), phần tử lớn nhất nằm ở cuối (rbegin).
while (cur.second <= 0 && !ms[u].empty()) {
// Lấy phần tử tốt nhất (cuối set)
auto it = prev(ms[u].end());
pair<long long, long long> best = *it;
ms[u].erase(it); // Xóa khỏi set
// Gộp vào job hiện tại
// Cost mới = min(cost cũ, tiền lời hiện có + cost của job con)
cur.first = min(cur.first, cur.second + best.first);
cur.second += best.second;
}
// Nếu sau khi gộp mà có lãi, đẩy lại vào set để cha của u sử dụng
if (cur.second > 0) {
ms[u].insert(cur);
}
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> init_money;
for (int i = 1; i <= n; ++i) {
cin >> a[i].first >> a[i].second;
adj[a[i].second].push_back(i);
}
DFS(0);
// Xử lý tại gốc 0: Chọn các việc làm được
// Duyệt từ việc dễ nhất (cost lớn nhất -> cuối set) về việc khó nhất
// Lưu ý: multiset không hỗ trợ pop_back như vector, ta dùng reverse iterator
for (auto it = ms[0].rbegin(); it != ms[0].rend(); ++it) {
auto [cost, earn] = *it;
// Kiểm tra xem có đủ tiền để bắt đầu chuỗi công việc này không
// init_money + res là tổng tiền hiện có
// cost là số âm, ví dụ -10. Ta cần tiền >= 10 <=> tiền + (-10) >= 0
if (init_money + res + cost < 0) {
// Nếu việc dễ nhất (ưu tiên nhất) không làm được thì các việc khó hơn cũng chịu
break;
}
res += earn;
}
cout << res;
return 0;
}
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |
| # | Verdict | Execution time | Memory | Grader output |
|---|
| Fetching results... |