前言

众所周知,90%90\%90%的题目与解法毫无关系。


题意

有一棵有根树,两种操作。一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和。


分析

很容易看出是树链剖分+线段树的题目,唯一的问题就是多条路径可能有交集。那么我们只要把每条路径拆成多个部分,每一部分是某重链上连续的一段,就得到了很多区间。然后排序取并集就能在线段树上操作了。

AC CODE

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
const int mod = 2147483647;
int n, m;
struct SegmentTree {
int v[MAXN<<2], lz[MAXN<<2], l[MAXN<<2], r[MAXN<<2], len[MAXN<<2];
inline void pushdown(int i) {
if(lz[i]) {
v[i<<1] += lz[i]*len[i<<1], lz[i<<1] += lz[i];
v[i<<1|1] += lz[i]*len[i<<1|1], lz[i<<1|1] += lz[i];
lz[i] = 0;
}
}
void build(int i, int L, int R) {
l[i] = L, r[i] = R, len[i] = R-L+1;
if(L == R) return;
build(i<<1, L, (L+R)>>1);
build(i<<1|1, (L+R)/2+1, R);
}
void Modify(int i, int L, int R, int k) {
if(L <= l[i] && r[i] <= R) { v[i] += k*len[i], lz[i] += k; return; }
pushdown(i);
int mid = (l[i] + r[i]) >> 1;
if(L <= mid) Modify(i<<1, L, R, k);
if(R > mid) Modify(i<<1|1, L, R, k);
v[i] = v[i<<1] + v[i<<1|1];
}
int Query(int i, int L, int R) {
if(L <= l[i] && r[i] <= R) return v[i];
pushdown(i);
int mid = (l[i] + r[i]) >> 1, res = 0;
if(L <= mid) res += Query(i<<1, L, R);
if(R > mid) res += Query(i<<1|1, L, R);
return res;
}
}T;
int fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt;
inline void add(int x, int y) {
to[++cnt] = y; nxt[cnt] = fir[x]; fir[x] = cnt;
}
int dep[MAXN], top[MAXN], dfn[MAXN], hson[MAXN], sz[MAXN], fa[MAXN];
inline void read(int &num) {
char ch; while((ch=getchar())<'0'||ch>'9');
for(num=0;ch>='0'&&ch<='9';num=num*10+ch-'0',ch=getchar());
}
struct node {
int l, r;
inline bool operator <(const node &t)const {
return l == t.l ? r > t.r : l < t.l;
}
}a[MAXN], b[MAXN];
int cur;
inline void pre(int x, int y) {
while(top[x] != top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
a[++cur] = (node){ dfn[top[x]], dfn[x] };
x = fa[top[x]];
}
if(dep[x] < dep[y]) swap(x, y);
a[++cur] = (node){ dfn[y], dfn[x] };
}
inline int solve() {
sort(a + 1, a + cur + 1);
int tot = 0, res = 0, l = a[1].l, r = a[1].r;
for(int i = 1; i <= cur; ++i)
if(a[i].r > r) {
if(a[i].l > r+1) b[++tot] = (node){ l, r }, l = a[i].l, r = a[i].r;
else r = a[i].r;
}
b[++tot] = (node){ l, r };
for(int i = 1; i <= tot; ++i)
res = (res + T.Query(1, b[i].l, b[i].r)) & mod;
return res;
} inline void dfs(int u, int ff) {
dep[u] = dep[fa[u]=ff] + (sz[u]=1);
for(int i = fir[u]; i; i = nxt[i])
if(to[i] != fa[u]) {
dfs(to[i], u), sz[u] += sz[to[i]];
if(sz[to[i]] > sz[hson[u]]) hson[u] = to[i];
}
} inline void dfs2(int u, int tp) {
top[u] = tp; dfn[u] = ++cur;
if(hson[u]) dfs2(hson[u], tp);
for(int i = fir[u]; i; i = nxt[i])
if(to[i] != fa[u] && to[i] != hson[u])
dfs2(to[i], to[i]);
} int main () {
read(n);
for(int i = 1, x, y; i < n; ++i)
read(x), read(y), add(x, y), add(y, x);
dfs(1, 0); dfs2(1, 1);
T.build(1, 1, n);
read(m);
int opt, x, y;
while(m--) {
read(opt);
if(!opt) read(x), read(y), T.Modify(1, dfn[x], dfn[x]+sz[x]-1, y);
else {
read(opt); cur = 0;
while(opt--) read(x), read(y), pre(x, y);
printf("%d\n", solve());
}
}
}

UpdUpdUpd

不要问我中间为什么不取模。因为懒。能过就行


EOFEOFEOF

BZOJ 3589 动态树 (树链剖分+线段树)的更多相关文章

  1. BZOJ.1758.[WC2010]重建计划(分数规划 点分治 单调队列/长链剖分 线段树)

    题目链接 BZOJ 洛谷 点分治 单调队列: 二分答案,然后判断是否存在一条长度在\([L,R]\)的路径满足权值和非负.可以点分治. 对于(距当前根节点)深度为\(d\)的一条路径,可以用其它子树深 ...

  2. 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp

    题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...

  3. 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp

    题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...

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

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

  5. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  6. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

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

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

  8. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  9. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

随机推荐

  1. pgsql常用操作

    pgsql备份: --进入pgsql容器docker exec -it 容器ID bash --备份pgsql /opt/rh/rh-postgresql95/root/usr/bin/pg_dump ...

  2. nohup启动后台进程并重定向

    一:linux重定向 0,1,2分别表示标准输入,标准输出和标准错误输出,一般情况下默认是标准输出 a. 1>log:标准输出重定向的log文件 b. 2>log:错误输出重定向到log文 ...

  3. 顺序表添加与删除元素以及 php实现顺序表实例

    对顺序表的操作,添加与删除元素. 增加元素 如下图所示  对顺序列表 Li [1328,693,2529,254]  添加一个元素 111 ,有三种方式: a)尾部端插入元素,时间复杂度O(1);  ...

  4. python可变类型与不可变类型

    一.可变类型与不可变类型的特点 1.不可变数据类型 不可变数据类型在第一次声明赋值声明的时候, 会在内存中开辟一块空间, 用来存放这个变量被赋的值,  而这个变量实际上存储的, 并不是被赋予的这个值, ...

  5. 20191030-带返回值的回溯算法Leetcode解数独

    题目描述 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次. 数字 1-9 在每一列只能出现一次. 数字 1-9 在每一个以粗实线分隔 ...

  6. python将url转变成二维码图片

    将url数据转变成二维码数据,再将二维码图片转成base64格式返回 import qrcode import io def url_image(self,url): img = qrcode.mak ...

  7. Python面试题集合带答案

    目录 Python基础篇 1:为什么学习Python 2:通过什么途径学习Python 3:谈谈对Python和其他语言的区别 Python的优势: 4:简述解释型和编译型编程语言 5:Python的 ...

  8. Tokitsukaze and Duel CodeForces - 1191E (博弈论)

    大意: 给定01串, 两人轮流操作, Tokitsukaze先手. 每次操作可以选择长为$k$的区间, 全部替换为$0$或$1$, 若替换后同色则赢. 求最后结果. 先判断第一步是否能直接赢, 不能的 ...

  9. (三)XML基础(3):Xpath

    五.XPath:快速定位到节点 5.1 简介 5.2 语法 5.3 案例 XPath对有命名空间的xml文件和没有命名空间的xml定位节点的方法是不一样的,所以再对不同的xml需要进行不同的处理. 使 ...

  10. CCF 201803-1 跳一跳

    题目: 问题描述 近来,跳一跳这款小游戏风靡全国,受到不少玩家的喜爱. 简化后的跳一跳规则如下:玩家每次从当前方块跳到下一个方块,如果没有跳到下一个方块上则游戏结束. 如果跳到了方块上,但没有跳到方块 ...