题目链接

题目

题目描述

一棵树上有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

题解

知识点:树链剖分,线段树。

这是一道树剖的板题,只需要最基本的查询修改即可。

通常树剖是对点维护,按链处理线段树。每次跳到下一条链的起点,维护整段链。

时间复杂度 \(O(n \log n + q\log ^2n)\)

空间复杂度 \(O(n)\)

代码

#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;
}

NC20477 [ZJOI2008]树的统计COUNT的更多相关文章

  1. BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14302  Solved: 5779[Submit ...

  2. bzoj1036 [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 12646  Solved: 5085 [Subm ...

  3. BZOJ 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 14354  Solved: 5802 [Subm ...

  4. 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

    [BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...

  5. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit ...

  6. Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 11102  Solved: 4490[Submit ...

  7. 数据结构(LCT动态树):BZOJ 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 12266  Solved: 4945[Submit ...

  8. BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )

    树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...

  9. 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 7496  Solved: 3078[Submit] ...

  10. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

    [ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...

随机推荐

  1. Mycat 实现分库分表及读写分离

    本文为博主原创,未经允许不得转载: Mycat 官网: http://mycat.org.cn/ MyCat 权威指南 文档:http://www.mycat.org.cn/document/myca ...

  2. 01-UPF介绍

    Mainstream Low Power techniques clock gating - 低功耗的设计风格,4bit以上可以通过综合工具增加ICG APR的时候可以更换器件VT Advanced ...

  3. k8s~istio的安装与核心组件

    安装istio 在线安装:https://istio.io/latest/docs/setup/getting-started/#download 或者直接在这里下载:https://github.c ...

  4. [转帖]《Linux性能优化实战》笔记(20)—— 使用 tcpdump 和 Wireshark 分析网络流量

    tcpdump 和 Wireshark 是最常用的网络抓包和分析工具,更是分析网络性能必不可少的利器. tcpdump 仅支持命令行格式使用,常用在服务器中抓取和分析网络包.Wireshark 除了可 ...

  5. [转帖]《Linux性能优化实战》笔记(21)—— 网络性能优化思路

    一. 确定优化目标 优化前,我会先问问自己,网络性能优化的目标是什么?实际上,虽然网络性能优化的整体目标,是降低网络延迟(如 RTT)和提高吞吐量(如BPS 和 PPS),但具体到不同应用中,每个指标 ...

  6. [转帖]VMware ESXi 各版本号对照表

    本博文转自以下链接: VMware ESXi Release and Build Number History | virten.net vSphere ESXi 7.0 Name Patch Dat ...

  7. [转帖]/proc文件简介

    https://www.jianshu.com/p/2610241770be 简介 /proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文件系统的方式为访问系统内核数据的操作提 ...

  8. [转帖]如何提高Linux下块设备IO的整体性能?

    http://www.yunweipai.com/6989.html 运维派隶属马哥教育旗下专业运维社区,是国内成立最早的IT运维技术社区,欢迎关注公众号:yunweipai领取学习更多免费Linux ...

  9. Python学习之十八_获取神通数据库所有的表数据量

    Python学习之十八_获取神通数据库所有的表数据量 背景 今天想获取一下所有数据库的表信息.但是发现神通数据库的系统表里面的表信息不正确 无法获取实际意义的表信息. 联系了下神通数据库的原厂高手. ...

  10. [转帖]Optimizing Block Device Parameter Settings of Linux

    https://support.huawei.com/enterprise/en/doc/EDOC1000181485/ddbc0e8b/optimizing-block-device-paramet ...