CF932D Tree
题目
见链接。
题解
知识点:倍增。
注意到,题目其实要求我们,每次要选最近一个权值大于等于自己的祖先,可以看出固定点生成出来的序列是固定的。因此,考虑设 为从 出发按规则向上走 次的点,设 为从 出发按规则向上走 次的所有序列点的权值和。
对于查询,需要注意要手动避免越界的 号节点问题,其余和正常倍增一致。
对于修改,由于是尾部追加,因此倍增可以支持,需要先确定向上第一个点是谁:
- 若新加点比它父亲小,那么直接设为它父亲。
- 否则,从父亲出发生成的序列中,找到比自己大的第一个点,显然可以用倍增找到。
随后更新一下倍增数组即可。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 400007; int cnt; int a[N]; int f[27][N]; ll b[27][N]; void update(int u, ll w) { a[++cnt] = w; if (a[u] >= a[cnt]) { f[0][cnt] = u; b[0][cnt] = a[u]; } else { for (int i = 20;i >= 0;i--) { if (!f[i][u]) continue; if (a[f[i][u]] < a[cnt]) u = f[i][u]; } f[0][cnt] = f[0][u]; b[0][cnt] = a[f[0][u]]; } for (int i = 1;i <= 20;i++) { f[i][cnt] = f[i - 1][f[i - 1][cnt]]; b[i][cnt] = b[i - 1][cnt] + b[i - 1][f[i - 1][cnt]]; } } int get_ans(int u, ll k) { if (a[u] > k) return 0; int ans = 1; ll sum = a[u]; for (int i = 20;i >= 0;i--) { if (!f[i][u]) continue; if (sum + b[i][u] <= k) { sum += b[i][u]; ans += 1 << i; u = f[i][u]; } } return ans; } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); ++cnt; int Q; cin >> Q; ll last = 0; while (Q--) { int op; ll p, q; cin >> op >> p >> q; if (op == 1) { int r = p ^ last; ll w = q ^ last; update(r, w); } else { int r = p ^ last; ll x = q ^ last; cout << (last = get_ans(r, x)) << '\n'; } } return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17499071.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
2022-06-23 NC50038 kotori和糖果
2022-06-23 Contest
2022-06-23 NC19115 选择颜色
2022-06-23 NC23046 华华教月月做数学
2022-06-23 NC14731 逆序对
2022-06-23 NC15052 求最值
2022-06-23 NC50999 表达式计算4