NC20477 [ZJOI2008]树的统计COUNT
题目
题目描述
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成 一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
输入描述
输入的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有 一条边相连。
接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1 ≤ n ≤ 30000,0 ≤ q ≤ 200000;中途操作中保证每个节点的权值w在-30000到30000之间。
输出描述
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
示例1
输入
4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2 3 QSUM 3 4 QSUM 2 1 CHANGE 1 5 QMAX 3 4 CHANGE 3 6 QMAX 3 4 QMAX 2 4 QSUM 3 4
输出
4 1 2 2 10 6 5 6 5 16
题解
知识点:树链剖分,线段树。
这是一道树剖的板题,只需要最基本的查询修改即可。
通常树剖是对点维护,按链处理线段树。每次跳到下一条链的起点,维护整段链。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; struct HLD { vector<int> siz, dep, fat, son, top, dfn, L, R; HLD() {} HLD(int rt, const vector<vector<int>> &g) { init(rt, g); } void init(int rt, const vector<vector<int>> &g) { assert(g.size()); int n = g.size() - 1; siz.assign(n + 1, 0); dep.assign(n + 1, 0); fat.assign(n + 1, 0); son.assign(n + 1, 0); top.assign(n + 1, 0); dfn.assign(n + 1, 0); L.assign(n + 1, 0); R.assign(n + 1, 0); function<void(int, int)> dfsA = [&](int u, int fa) { siz[u] = 1; dep[u] = dep[fa] + 1; fat[u] = fa; for (auto &v : g[u]) { if (v == fa) continue; dfsA(v, u); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } }; dfsA(rt, 0); int dfncnt = 0; function<void(int, int)> dfsB = [&](int u, int tp) { top[u] = tp; dfn[++dfncnt] = u; L[u] = dfncnt; if (son[u]) dfsB(son[u], tp); for (auto v : g[u]) { if (v == fat[u] || v == son[u]) continue; dfsB(v, v); } R[u] = dfncnt; }; dfsB(rt, rt); } }; template<class T, class F> struct SegmentTree { int n; vector<T> node; void update(int rt, int l, int r, int x, F f) { if (r < x || x < l) return; if (l == r) return node[rt] = f(node[rt]), void(); int mid = l + r >> 1; update(rt << 1, l, mid, x, f); update(rt << 1 | 1, mid + 1, r, x, f); node[rt] = node[rt << 1] + node[rt << 1 | 1]; } T query(int rt, int l, int r, int x, int y) { if (r < x || y < l) return T::e(); if (x <= l && r <= y) return node[rt]; int mid = l + r >> 1; return query(rt << 1, l, mid, x, y) + query(rt << 1 | 1, mid + 1, r, x, y); } public: SegmentTree(int _n = 0) { init(_n); } SegmentTree(const vector<T> &src) { init(src); } void init(int _n) { n = _n; node.assign(n << 2, T::e()); } void init(const vector<T> &src) { assert(src.size() >= 2); init(src.size() - 1); function<void(int, int, int)> build = [&](int rt, int l, int r) { if (l == r) return node[rt] = src[l], void(); int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); node[rt] = node[rt << 1] + node[rt << 1 | 1]; }; build(1, 1, n); } void update(int x, F f) { update(1, 1, n, x, f); } T query(int x, int y) { return query(1, 1, n, x, y); } }; struct T { int sum; int mx; static T e() { return { 0,(int)-1e9 }; } friend T operator+(const T &a, const T &b) { return { a.sum + b.sum,max(a.mx,b.mx) }; } }; struct F { int upd; T operator()(const T &x) { return { upd,upd }; } }; const int N = 3e4 + 7; vector<int> g[N]; HLD hld; SegmentTree<T, F> sgt; void node_update(int u, int w) { sgt.update(hld.L[u], { w }); } int path_max(int u, int v) { auto &top = hld.top; auto &dep = hld.dep; auto &fat = hld.fat; auto &L = hld.L; int ans = -1e9; while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); ans = max(ans, sgt.query(L[top[u]], L[u]).mx); u = fat[top[u]]; } if (dep[u] > dep[v]) swap(u, v); ans = max(ans, sgt.query(L[u], L[v]).mx); return ans; } int path_sum(int u, int v) { auto &top = hld.top; auto &dep = hld.dep; auto &fat = hld.fat; auto &L = hld.L; int ans = 0; while (top[u] != top[v]) { if (dep[top[u]] < dep[top[v]]) swap(u, v); ans += sgt.query(L[top[u]], L[u]).sum; u = fat[top[u]]; } if (dep[u] > dep[v]) swap(u, v); ans += sgt.query(L[u], L[v]).sum; return ans; } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 1;i <= n - 1;i++) { int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } hld.init(1, vector<vector<int>>(g, g + n + 1)); vector<T> a(n + 1); for (int i = 1;i <= n;i++) { int x; cin >> x; a[hld.L[i]] = { x,x }; } sgt.init(a); int q; cin >> q; while (q--) { string op; cin >> op; if (op == "CHANGE") { int u, t; cin >> u >> t; node_update(u, t); } else if (op == "QMAX") { int u, v; cin >> u >> v; cout << path_max(u, v) << '\n'; } else { int u, v; cin >> u >> v; cout << path_sum(u, v) << '\n'; } } return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17499122.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
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