题意
传送门 Codeforces 1535E old Transfer
题解
节点 u u u 的单位黄金花费严格大于祖先节点。那么根据贪心策略,对任意花费最小的购买,一定从祖先节点开始。
问题转化为如何高效求解任一节点至根节点路径上剩余黄金数量非零且深度最小的节点。参考倍增 L C A LCA LCA 的思路,预处理出节点 u u u 的 2 k 2^k 2k 辈祖先,即可 O ( log q ) O(\log q) O(logq) 求出这样的节点。总时间复杂度 O ( q log q ) O(q\log q) O(qlogq)。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
typedef long long ll;
const int MAX_Q = 300005, MAX_LOG_N = 19;
int Q, A[MAX_Q], C[MAX_Q];
int dep[MAX_Q], lg[MAX_Q], par[MAX_LOG_N][MAX_Q];
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> Q >> A[0] >> C[0];
dep[0] = 0;
lg[0] = -1;
rep(i, 1, MAX_Q) lg[i] = lg[i >> 1] + 1;
rep(i, 1, Q + 1)
{
int op;
cin >> op;
if (op == 1)
{
int p;
cin >> p >> A[i] >> C[i];
dep[i] = dep[p] + 1;
par[0][i] = p;
rep(j, 1, lg[dep[i]] + 1) par[j][i] = par[j - 1][par[j - 1][i]];
}
else
{
int v, w;
cin >> v >> w;
ll num = 0, cost = 0;
while (w > 0 && A[v] > 0)
{
int u = v;
for (int k = lg[dep[u]]; k >= 0;)
if (A[par[k][u]] > 0)
u = par[k][u], k = lg[dep[u]];
else
--k;
int d = min(w, A[u]);
A[u] -= d, w -= d;
num += d, cost += (ll)d * C[u];
}
cout << num << ' ' << cost << endl;
}
}
return 0;
}