CF EDU 110 - E - Gold Transfer

E - Gold Transfer

树上倍增 + 贪心

由于 \(c_i>c_{p_i}\), 所以一定是把结点祖先的黄金采完才会采这个结点的,因此某个点有无黄金这个性质具有单调性,靠近根的一侧没有,靠近叶子的有,所以可以倍增查到某个结点上方离根最近的有黄金的结点,从该点开始采

由于一个点被采完才会到他的儿子,每个点不会补充黄金,所以它只会被采空一次,所以总复杂度为 \(O(nlogn)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;

const int N = 3e5 + 10;
int q;
int a[N], c[N];
int f[N][22];//f[i][j]为i结点向上第2^j个祖先的编号
int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> q >> a[0] >> c[0];
	
	for (int i = 1; i <= q; i++)
	{
		int op;
		cin >> op;
		if (op == 1)
		{
			int p;
			cin >> p >> a[i] >> c[i];
			f[i][0] = p;
			for (int j = 1; j <= 20; j++)
				f[i][j] = f[f[i][j-1]][j-1];
		}
		else
		{
			int v, w;
			cin >> v >> w;
			ll cnt = 0, cost = 0;
			while(w && a[v] > 0)
			{
				int u = v;
				for (int j = 20; j >= 0; j--)
					if (a[f[u][j]] > 0)
						u = f[u][j];
				int k = min(w, a[u]);
				w -= k, a[u] -= k;
				cnt += k, cost += 1ll * k * c[u];
			}
			cout << cnt << " " << cost << endl;
		}
	}
	return 0;
}
posted @ 2022-05-16 22:09  hzy0227  阅读(34)  评论(0编辑  收藏  举报