NC232181. 露西、天空与钻石
描述
天空中有许多钻石。
露西发现天空中的钻石总是呈一个树形结构。
开始天空中有一个根节点(编号为 ),根节点上有 个钻石,每个钻石的美丽程度都是 。
天空中发生了 个事件,第 个事件有两种:
对于每种二号事件,你要求出摘到的钻石数量和最大美丽之和。
输入描述
本题强制在线。
第一行三个整数 (),分别表示事件个数,根节点上钻石个数和美丽程度。
接下来 行,第 行的输入为以下两种格式中的一种:
(),表示发生了事件一。其中 为 加密后的结果,真实的 , 为上一次询问中两个问题的答案之和,如果没有上一次询问则 。
(),表示发生了事件二。
操作含义详见题目描述,保证操作中节点 存在。
输出描述
对于每个二号事件,一行两个整数分别表示摘到的钻石数和美丽程度之和。
示例1
输入:
10 10 1 2 0 7 1 0 4 4 1 0 2 8 1 1 4 7 1 0 2 7 2 5 15 1 3 3 4 1 1 5 5 1 5 3 3 2 9 9
输出:
7 7 15 77 6 21
说明:
强制在线前的输入:
10 10 1
2 0 7
1 0 4 4
1 2 2 8
1 3 4 7
1 4 2 7
2 5 15
1 4 3 4
1 5 5 5
1 7 3 3
2 9 9
C++ 解法, 执行用时: 596ms, 内存消耗: 6432K, 提交时间: 2022-03-10 21:23:54
#include <bits/stdc++.h> const int MaxN = 2e5 + 5; int q, a[MaxN], c[MaxN]; int fa[MaxN], ch[MaxN][2], mx[MaxN]; void pushup(int x) { mx[x] = x; for(int p : {ch[x][0], ch[x][1]}) if(std::tie(a[mx[p]], mx[p]) > std::tie(a[mx[x]], mx[x])) mx[x] = mx[p]; } bool isroot(int x) {return ch[fa[x]][0] != x && ch[fa[x]][1] != x;} int get(int x) {return (ch[fa[x]][0] == x ? 0 : 1);} void rotate(int x) { int k = get(x), y = fa[x], z = fa[y]; if(!isroot(y)) ch[z][get(y)] = x; ch[y][k] = ch[x][k ^ 1]; fa[ch[y][k]] = y; ch[x][k ^ 1] = y; fa[y] = x; fa[x] = z; pushup(y); pushup(x); } void splay(int x) { for(int f = fa[x]; !isroot(x); rotate(x), f = fa[x]) if(!isroot(f)) rotate(get(x) == get(f) ? f : x); } void access(int x) { for(int p = 0; x; p = x, x = fa[x]) splay(x), ch[x][1] = p, pushup(x); } int main() { int64_t lastans = 0; std::cin >> q >> c[1] >> a[1]; pushup(1); for(int i = 1, opt, f, v, w; i <= q; ++i) { std::cin >> opt; if(opt == 1) { std::cin >> f >> c[i + 1] >> a[i + 1]; fa[i + 1] = (f + lastans) % i + 1; pushup(i + 1); } else { std::cin >> v >> w; ++v; access(v); int cnt = 0; int64_t sum = 0; while(true) { splay(v); int t = mx[v]; if(a[t] == 0) break; int x = std::min(c[t], w); cnt += x; sum += int64_t(x) * a[t]; if((c[t] -= x) == 0) splay(t), a[t] = 0, pushup(t); if((w -= x) == 0) break; } std::cout << cnt << " " << sum << "\n"; lastans = cnt + sum; } } return 0; }