Submission #1309826

#TimeUsernameProblemLanguageResultExecution timeMemory
1309826harryleeeJobs (BOI24_jobs)C++20
40 / 100
260 ms86064 KiB
#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 timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...