洛谷P2590 [ZJOI2008]树的统计 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P2590
树链剖分模板题。
剖分过程要用到如下7个值:
fa[u]
:u的父节点编号;dep[u]
:u的深度;size[u]
:u为根的子树中节点总数;son[u]
:u的重儿子;top[u]
:u所在的重链的顶部节点;seg[u]
:u在线段树中的位置;rev[u]
:seg的倒置,即rev[seg[u]] == u
。
然后套线段树模板实现区间最值、区间和,及单点更新操作。
实现代码如下:
#include <bits/stdc++.h>
using namespace std;
#define INF (1<<29)
const int maxn = 30030;
int fa[maxn],
dep[maxn],
size[maxn],
son[maxn],
top[maxn],
seg[maxn], seg_cnt,
rev[maxn],
n, w[maxn], maxv[maxn<<2], sumv[maxn<<2];
vector<int> g[maxn];
void dfs1(int u, int p) {
size[u] = 1;
for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it ++) {
int v = (*it);
if (v == p) continue;
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v, u);
size[u] += size[v];
if (size[v] >size[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
seg[u] = ++seg_cnt;
rev[seg_cnt] = u;
top[u] = tp;
if (son[u]) dfs2(son[u], tp);
for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it ++) {
int v = (*it);
if (v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
void push_up(int rt) {
sumv[rt] = sumv[rt<<1] +sumv[rt<<1|1];
maxv[rt] = max(maxv[rt<<1], maxv[rt<<1|1]);
}
void build(int l, int r, int rt) {
int mid = (l + r) / 2;
if (l == r) {
sumv[rt] = maxv[rt] = w[rev[l]];
return;
}
build(lson); build(rson);
push_up(rt);
}
void update(int p, int v, int l, int r, int rt) {
if (l == r) {
sumv[rt] = maxv[rt] = v;
return;
}
int mid = (l + r) / 2;
if (p <= mid) update(p, v, lson);
else update(p, v, rson);
push_up(rt);
}
int query_max(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return maxv[rt];
int mid = (l + r) / 2, tmp = -INF;
if (L <= mid) tmp = max(tmp, query_max(L, R, lson));
if (R > mid) tmp = max(tmp, query_max(L, R, rson));
return tmp;
}
int query_sum(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return sumv[rt];
int mid = (l + r) / 2, tmp = 0;
if (L <= mid) tmp += query_sum(L, R, lson);
if (R > mid) tmp += query_sum(L, R, rson);
return tmp;
}
int ask_max(int u, int v) {
int res = -INF;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
res = max(res, query_max(seg[top[u]], seg[u], 1, n, 1));
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
res = max(res, query_max(seg[v], seg[u], 1, n, 1));
return res;
}
int ask_sum(int u, int v) {
int res = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
res += query_sum(seg[top[u]], seg[u], 1, n, 1);
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
res += query_sum(seg[v], seg[u], 1, n, 1);
return res;
}
int m;
string s;
int main() {
cin >> n;
for (int i = 1; i < n; i ++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 1; i <= n; i ++) cin >> w[i];
dep[1] = fa[1] = 1;
dfs1(1, -1);
dfs2(1, 1);
build(1, n, 1);
cin >> m;
while (m --) {
int u, v;
cin >> s >> u >> v;
if (s == "CHANGE") update(seg[u], v, 1, n, 1);
else if (s == "QMAX") cout << ask_max(u, v) << endl;
else cout << ask_sum(u, v) << endl;
}
return 0;
}
洛谷P2590 [ZJOI2008]树的统计 题解 树链剖分+线段树的更多相关文章
- 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点
题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...
- 洛谷P2486 [SDOI2011]染色 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P2486 首先这是一道树链剖分+线段树的题. 线段树部分和 codedecision P1112 区间连续段 一模一样,所以我们 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- 【bzoj1036】树的统计[ZJOI2008]树链剖分+线段树
题目传送门:1036: [ZJOI2008]树的统计Count 这道题是我第一次打树剖的板子,虽然代码有点长,但是“打起来很爽”,而且整道题只花了不到1.5h+,还是一遍过样例!一次提交AC!(难道前 ...
- 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树
正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...
- BZOJ.1758.[WC2010]重建计划(分数规划 点分治 单调队列/长链剖分 线段树)
题目链接 BZOJ 洛谷 点分治 单调队列: 二分答案,然后判断是否存在一条长度在\([L,R]\)的路径满足权值和非负.可以点分治. 对于(距当前根节点)深度为\(d\)的一条路径,可以用其它子树深 ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
- 【CF725G】Messages on a Tree 树链剖分+线段树
[CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...
随机推荐
- listview显示固定条数
看了很多网上其他大神的,感觉还是在listview的adapter中的getCount中下手比较好点 毕竟计算高度等等,那会让辅助的布局会一团糟,例如下面的搜索历史只显示四条,布局中有横向listvi ...
- CEF 框架使用集锦
CEF 框架使用集锦: 参考:〓https://github.com/NetDimension/NanUI/wiki/%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8NanUI ...
- objectarx MFC 非模态对话框为当前焦点
dialog.h afx_msg LRESULT OnAcadKeepFocus(WPARAM, LPARAM); dialog.cpp BEGIN_MESSAGE_MAP(CTextDialog, ...
- SQL优化系列(三)- 用最少的索引获得最大的性能提升
从全局出发优化索引 对于高负载的数据库,如何创建最少的索引,让数据库的整体性能提高呢?例如,对于100 条SQL语句,如何创建最佳的5条索引? SQL自动优化工具SQL Tuning Expert P ...
- Leetcode762.Prime Number of Set Bits in Binary Representation二进制表示中质数个计算置位
给定两个整数 L 和 R ,找到闭区间 [L, R] 范围内,计算置位位数为质数的整数个数. (注意,计算置位代表二进制表示中1的个数.例如 21 的二进制表示 10101 有 3 个计算置位.还有, ...
- jquery的innerWidth 和 innerHeight的使用
innerWidth This method returns the width of the element, including left and right padding, in pixels ...
- ie6中兼容性问题总结
针对firefox ie6 ie7 ie8的css样式中的line-height属性,以前我们大部分都是用!important来hack,对于ie6和firefox测试可以正常显示,但是ie7以上对! ...
- Servlet小结(转载)
http://www.iteye.com/topic/766418 1 .首先,什么是Servlet? Servlet是一个Java编写的程序,此程序是在服务器端运行的,是按照Servl ...
- 学习iOS设计--iOS8的颜色、文字和布局学习
在去年,Apple针对新时代用户彻底更新了其设计语言.现在的设计语言相对之前大为简化,能够让设计师将精力集中到动画和功能上,而不是繁复的视觉细节上. 很多人都曾问过我:设计应当如何入门?成为一名优秀设 ...
- day39-Spring 03-JDK的动态代理
package cn.itcast.spring3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Meth ...