题目链接:传送门
思路:
分析到处理节点时的吃cookie的顺序了,然鹅不会用线段树维护前缀和。技术门槛QAQ。。。
很容易想到可以从root开始搜索,每次深入消耗时间2*边权w。
然后对于深入到点u开始返回的话,想要尽量多地吃cookie,就要贪心地选择用时短的cookie,也就是:
当前节点为u,剩余时间为val时,最多能在1-u这条链上吃到多少个cookie。
一共有1e6个节点,所以这个贪心策略的实现复杂度要压到log级别。。。好难不会。
思路参考:Dream_maker_yk的博客
线段树维护前缀和。
首先我们以时间ti为坐标向线段树中插入节点。保存两个值,把子树吃光所用的总时间sum,子树中的cookie总数cnt。
然后根据剩余时间val查询,如果左子树的sum比val小,那么说明左子树可以吃光,那么查询结果就是:
cnt左子树 + 对右子树查询val - sum左子树
这样我们就可以用logn的时间实现贪心策略了。
然后考虑到Vasya会干扰我们,所以应题目要求,我们要求在Vasya干扰得最好的情况下,能吃到的最大的cookie数量。
最差的情况就是Vasya每次深入后都把最好的子树f1给办掉了,那么我们只能选次好的子树f2。
因为每个节点都可能返回,所以回溯当前节点的最多cookie数ans。而当前节点的最多cookie数可能是吃到当前节点为止,也可能是吃到当前节点的子树,所以ans = max(ans,f2)。
特别地,因为Mitya是先手,所以root的子树不会被办,ans = max(ans,f1)。
代码:
#include <bits/stdc++.h> #define lson (pos << 1) #define rson (pos << 1 | 1) using namespace std; typedef long long ll; const int MAX_N = 1e6 + 5; struct Edge{ int v; ll w; }; ll x[MAX_N], t[MAX_N]; vector <Edge> g[MAX_N]; ll sum[MAX_N<<2], cnt[MAX_N<<2]; void update(int pos, int l, int r, ll xi, ll ti) { sum[pos] += xi*ti; cnt[pos] += xi; if (l == r) return; int mid = (l + r) >> 1; if (ti <= mid) update(lson, l, mid, xi, ti); else update(rson, mid+1, r, xi, ti); } ll query(int pos, int l, int r, ll val) { if (l == r) return min(cnt[pos], val/l); int mid = (l + r) >> 1; if (sum[lson] <= val) return cnt[lson] + query(rson, mid+1, r, val - sum[lson]); else return query(lson, l, mid, val); } ll dfs(int u, ll res) { update(1, 1, 1e6, x[u], t[u]); ll ans = query(1, 1, 1e6, res); ll f1 = 0, f2 = 0; for (const auto &tmp : g[u]) { int v = tmp.v; ll w = tmp.w; if (res < 2*w) continue; ll f = dfs(v, res - 2*w); if (f > f1) f2 = f1, f1 = f; else if (f > f2) f2 = f; } update(1, 1, 1e6, -x[u], t[u]); if (u == 1) return max(ans, f1); else return max(ans, f2); } int main() { std::ios::sync_with_stdio(false); cin.tie(nullptr); int n; ll T; cin >> n >> T; for (int i = 1; i <= n; i++) cin >> x[i]; for (int i = 1; i <= n; i++) cin >> t[i]; for (int u = 2; u <= n; u++) { int v; ll w; cin >> v >> w; g[v].push_back((Edge){u, w}); } ll ans = dfs(1, T); cout << ans << endl; return 0; }