题目链接:https://www.luogu.org/problem/P3178

这道题目是一道树链剖分的模板题。

但是在解决这道问题的同事刷新了我的两个认识:

第一个认识是:树链剖分不光可以处理链,还可以处理 子树 ,因为:

节点 u 的子树中所有的点的编号都覆盖在 seg[u]seg[u]+size[u]-1 这个区间内!

第二个认识是:线段树延迟操作的延迟标记不是标记自己,也就是说:

lazy[rt] 并不是标记本身的延迟值,而是说 rt 本身有多少个延迟值没有传递给 rt<<1rt<<1|1 的。

然后这道题目就是一道裸树链剖分题,运用到了子树更新和延迟操作。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
#define INF (1<<29)
const int maxn = 100010;
int fa[maxn],
dep[maxn],
size[maxn],
son[maxn],
top[maxn],
seg[maxn], seg_cnt,
rev[maxn],
n, w[maxn];
long long sumv[maxn<<2], lazy[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_down(int rt, int len) {
if (lazy[rt]) {
int l_len=len-len/2, r_len = len/2;
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
sumv[rt<<1] += lazy[rt] * l_len;
sumv[rt<<1|1] += lazy[rt] * r_len;
lazy[rt] = 0;
}
}
void push_up(int rt) {
sumv[rt] = sumv[rt<<1] + sumv[rt<<1|1];
}
void build(int l, int r, int rt) {
int mid = (l + r) / 2;
if (l == r) {
sumv[rt] = w[rev[l]];
return;
}
build(lson); build(rson);
push_up(rt);
}
void update(int L, int R, long long v, int l, int r, int rt) {
if (L <= l && r <= R) {
sumv[rt] += (r-l+1) * v;
lazy[rt] += v;
return;
}
push_down(rt, r-l+1);
int mid = (l + r) / 2;
if (L <= mid) update(L, R, v, lson);
if (R > mid) update(L, R, v, rson);
push_up(rt);
}
long long query_sum(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return sumv[rt];
push_down(rt, r-l+1);
int mid = (l + r) / 2;
long long tmp = 0;
if (L <= mid) tmp += query_sum(L, R, lson);
if (R > mid) tmp += query_sum(L, R, rson);
return tmp;
}
long long ask_sum(int u, int v) {
long long 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, op, x, a;
string s;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> w[i];
for (int i = 1; i < n; i ++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dep[1] = fa[1] = 1;
dfs1(1, -1);
dfs2(1, 1);
build(1, n, 1);
while (m --) {
cin >> op;
if (op == 1) {
cin >> x >> a;
update(seg[x], seg[x], a, 1, n, 1);
}
else if (op == 2) {
cin >> x >> a;
update(seg[x], seg[x]+size[x]-1, a, 1, n, 1);
}
else {
cin >> x;
cout << ask_sum(1, x) << endl;
}
}
return 0;
}

作者:zifeiy

洛谷P3178 [HAOI2015]树上操作 题解 树链剖分+线段树的更多相关文章

  1. 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)

    P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...

  2. 洛谷P3178 [HAOI2015]树上操作

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...

  3. 洛谷P3178 [HAOI2015]树上操作(线段树)

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...

  4. 洛谷 P4292 - [WC2010]重建计划(长链剖分+线段树)

    题面传送门 我!竟!然!独!立!A!C!了!这!道!题!incredible! 首先看到这类最大化某个分式的题目,可以套路地想到分数规划,考虑二分答案 \(mid\) 并检验是否存在合法的 \(S\) ...

  5. 洛谷 P3178 [HAOI2015]树上操作

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...

  6. 洛谷——P3178 [HAOI2015]树上操作

    https://www.luogu.org/problem/show?pid=3178#sub 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 ...

  7. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  8. 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点

    题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...

  9. 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树

    正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...

随机推荐

  1. 第八章—BOM(一)

    ECMAscript是JS的核心,而要在web上使用JS,那么BOM无疑是真正的核心.BOM叫浏览器对象模型,它提供了许多对象,用于访问浏览器的功能. BOM的核心对象是window,它表示浏览器的一 ...

  2. 【JZOJ3636】【BOI2012】Mobile(mobile)

    Mission 著名的手机网络运营商Totalphone 修建了若干基站收发台,以用于把信号网络覆盖一条新建的高速公路.因为Totalphone 的程序员总是很马虎的,所以,基站的传功功率不能独立设置 ...

  3. oracle 索引监控

           索引对于在大量数据里检索出少量数据库的查询操作来说是高效的,可是对于DML操作来说.却是负面的:①其对于insert 操作的反面影响最大.该表的索引越多,更新的索引越多,insert 操 ...

  4. c:if标签判断不为空和其他的值判断

    今天用<c:if test=""></c:if>标签时 <c:if test="${sl.chc_status==1 }"> ...

  5. MySQL数据库简单使用

    一.入门语句: 1.连接服务器: 命令:cd 安装目录\bin mysql -uroot -p 接着输入密码 ( 具体的是:mysql -u username-p password ) 远程连接MyS ...

  6. jpa hibernate 打印sql,format日志,打印SQL参数,打印什么指令

    环境说明:IntelliJ IDEA 2017.3.4 版本:SpringBoot 2.0.0.RELEASE:hibernate用的是JPA自带. 打印SQL 到控制台: 首先,我使用的是appli ...

  7. Spring boot通过JPA访问MySQL数据库

    本文展示如何通过JPA访问MySQL数据库. JPA全称Java Persistence API,即Java持久化API,它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据 ...

  8. qbao

    # -*- coding: utf-8 -*- import Image, cStringIO, webbrowser, re, time, math import urllib, urllib2, ...

  9. bzoj1877 晨跑

    Description Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止,他 坚持下来的只有晨跑. 现在给出一张学校附近的地图,这张地图中包含N个 ...

  10. 【7.18总结】KM算法

    先贴代码,参考博客来源于:https://blog.csdn.net/zyy173533832/article/details/11519291#commentBox 例题:HDU 2255 题意:n ...