Gold Transfer
算法
暴力算法还得排序
观察到重要信息
我们保证 \(c_i > c_{p_i}\) 成立
因此可以贪心, 从离根最近的点一路向北向下找到查询点
要快速找到最上方不为空的点, 联想到倍增法, 于是优化到 \(O(\log n)\)
总时间复杂度 \(O(n \log n)\)
代码
#include <bits/stdc++.h>
const int MAXN = 3e5 + 20;
#define int long long
struct node
{
int Val;
int Num;
} Tree[MAXN];
int fa[MAXN][30];
int q;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x * f;
}
void Fa_init(int Start)
{
for (int i = 1; i <= 20; i++)
{
if (~fa[Start][i - 1] && ~fa[fa[Start][i - 1]][i - 1])
fa[Start][i] = fa[fa[Start][i - 1]][i - 1];
}
}
int Min_Num, Min_Val;
void solve(int v, int w)
{
while (w)
{
if (!Tree[v].Num)
break;
/*找 >0 的节点*/
int Start = v;
for (int i = 20; i >= 0; i--)
{
if (~fa[Start][i])
if (Tree[fa[Start][i]].Num > 0)
{
Start = fa[Start][i];
}
}
/*计算(问题主要在找链上, 这里用循环方式解决)*/
int Buy_Num = std::min(Tree[Start].Num, w);
Min_Num += Buy_Num;
Min_Val += Buy_Num * Tree[Start].Val;
Tree[Start].Num -= Buy_Num;
w -= Buy_Num;
}
}
signed main()
{
int Val_root, Num_root;
q = read();
Num_root = read();
Val_root = read();
Tree[0].Num = Num_root, Tree[0].Val = Val_root;
for (int i = 0; i <= 20; i++)
{
fa[0][i] = -1;
}
for (int i = 1; i <= q; i++)
{
int op;
int Fa_now, Val_now, Num_now;
int v, w;
op = read();
if (op == 1)
{
Fa_now = read();
Num_now = read();
Val_now = read();
fa[i][0] = Fa_now;
Tree[i].Num = Num_now;
Tree[i].Val = Val_now;
Fa_init(i);
}
else
{
v = read();
w = read();
Min_Num = 0, Min_Val = 0;
solve(v, w);
printf("%lld %lld\n", Min_Num, Min_Val);
fflush(stdout);
}
}
return 0;
}
/*
5 5 2
2 0 2
1 0 3 4
2 2 4
1 0 1 3
2 4 2
2 4
4 10
1 3
*/
总结
观察题意优化代码
仔细读题

浙公网安备 33010602011771号