|
| 1 | +#include <bits/stdc++.h> |
| 2 | + |
| 3 | +using namespace std; // NOLINT |
| 4 | + |
| 5 | +constexpr int MAX_N = 5000; |
| 6 | + |
| 7 | +constexpr int MAX_B = 1000000000; |
| 8 | + |
| 9 | +constexpr int INF = MAX_B + 1; |
| 10 | + |
| 11 | +int n, b; |
| 12 | + |
| 13 | +int64_t C[MAX_N], D[MAX_N], X[MAX_N]; |
| 14 | + |
| 15 | +/** |
| 16 | + * T[u] = The set of coupons that can be used after using coupon u. |
| 17 | + */ |
| 18 | +vector<int> T[MAX_N]; |
| 19 | + |
| 20 | +/** |
| 21 | + * S[u] = The size of the sub-tree rooted at u. |
| 22 | + */ |
| 23 | +int S[MAX_N]; |
| 24 | + |
| 25 | +/** |
| 26 | + * F[u][i] = The minimum cost to buy exactly i items from the sub-tree rooted |
| 27 | + * at u using coupons. |
| 28 | + */ |
| 29 | +int64_t F[MAX_N][MAX_N + 1]; |
| 30 | + |
| 31 | +/** |
| 32 | + * G[u][i] = The minimum cost to buy exactly i items from the sub-tree rooted |
| 33 | + * at u WITHOUT using coupons. |
| 34 | + */ |
| 35 | +int64_t G[MAX_N][MAX_N + 1]; |
| 36 | + |
| 37 | +/** |
| 38 | + * Calculates F[v][*] and G[v][*] for all v in the sub-tree rooted at u. |
| 39 | + */ |
| 40 | +void dfs(int u) { |
| 41 | + assert(u >= 0 && u < n); |
| 42 | + |
| 43 | + // This is important to enforce coupon dependencies! Especially in line 58 |
| 44 | + // when i = 0 but we must buy/use coupon u to use coupons further down the |
| 45 | + // tree. |
| 46 | + F[u][0] = INF; |
| 47 | + F[u][1] = C[u] - D[u]; |
| 48 | + |
| 49 | + G[u][0] = 0; |
| 50 | + G[u][1] = C[u]; |
| 51 | + |
| 52 | + S[u] = 1; |
| 53 | + |
| 54 | + for (int v : T[u]) { |
| 55 | + dfs(v); |
| 56 | + |
| 57 | + for (int i = S[u]; i >= 0; i--) { |
| 58 | + for (int k = S[v]; k >= 0; k--) { |
| 59 | + // We can use a coupon if we bought the parent with a coupon. If we |
| 60 | + // also buy item u with a coupon then we can also make use of coupons |
| 61 | + // with purchases further down the tree. However we do not have to |
| 62 | + // use coupons - it may be cheaper to buy an undiscounted item far |
| 63 | + // down the tree with a cheap base price than buying all the items |
| 64 | + // leading up to it just to get a discount that does not make up for |
| 65 | + // the cost of the path. |
| 66 | + F[u][i + k] = min(F[u][i + k], F[u][i] + min(F[v][k], G[v][k])); |
| 67 | + |
| 68 | + // If we cannot use a coupon this property holds for all remaining |
| 69 | + // items in this sub-tree. |
| 70 | + G[u][i + k] = min(G[u][i + k], G[u][i] + G[v][k]); |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + S[u] += S[v]; |
| 75 | + } |
| 76 | +} |
| 77 | + |
| 78 | +/** |
| 79 | + * Calculates the maximum number of items that Karen can buy. |
| 80 | + */ |
| 81 | +int items() { |
| 82 | + std::fill(&F[0][0], &F[0][0] + sizeof(F)/ sizeof(F[0][0]), INF); |
| 83 | + std::fill(&G[0][0], &G[0][0] + sizeof(G)/ sizeof(G[0][0]), INF); |
| 84 | + |
| 85 | + // Calculate F and G. |
| 86 | + dfs(0); |
| 87 | + |
| 88 | + // Find most items that can be bought with budget b in O(log N) time. |
| 89 | + int s = 0, lo = 0, hi = n; |
| 90 | + |
| 91 | + while (lo <= hi) { |
| 92 | + int m = lo + (hi - lo) / 2; |
| 93 | + |
| 94 | + // Slice search window in half. |
| 95 | + if (F[0][m] <= b || G[0][m] <= b) { |
| 96 | + s = m; |
| 97 | + lo = m + 1; |
| 98 | + } else { |
| 99 | + hi = m - 1; |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + return s; |
| 104 | +} |
| 105 | + |
| 106 | +int main() { |
| 107 | + cin >> n >> b; |
| 108 | + |
| 109 | + assert(n <= MAX_N); |
| 110 | + |
| 111 | + cin >> C[0] >> D[0]; |
| 112 | + for (int u = 1; u < n; u++) { |
| 113 | + cin >> C[u] >> D[u] >> X[u]; |
| 114 | + X[u]--; |
| 115 | + T[X[u]].push_back(u); |
| 116 | + } |
| 117 | + |
| 118 | + cout << items() << endl; |
| 119 | + |
| 120 | + return 0; |
| 121 | +} |
0 commit comments