P6329 【模板】点分树 | 震波
\(\text{Solution}\)
点分树就是将点分治过程中的重心连成一棵虚树
对点分树子树信息的记录,就是点分治处理每个重心时需要的信息
这样就可以留下点分治的过程,支持多次修改和查询
点分树树高 \(O(log n)\) 且 \(\sum size_x = O(n \log n)\)
可以使用很多暴力的手段
但要注意:点分树和原树唯一的联系是点分树中两点的 \(LCA\) 在原树两点的路径上
\(LCA\) 的祖先和这两点的路径再无关系,容斥时要思考清楚
所以统计路径长一切行为以原树为准
因为要大量求 \(LCA\),所以用欧拉序转 \(RMQ\)
两点的 \(LCA\) 就是 \([\min(first_u,first_v),\max(first_u,first_v)]\) 中 \(dep\) 最小的点
注意:
欧拉序有两种:一个点入栈和出栈时记录,序列长 \(2n\)
一个点入栈记一次,每次回溯都记一次,考虑边数得序列长 \(2n-1\)
求 \(LCA\) 时用第二种
又:\(\text{vector}\) 的 \(\text{size()}\) 返回值为 \(\text{unsigned int}\),比较时将参与比较的元素强转 \(\text{unsigned int}\)
所以用负数比较会挂,这点让我懵逼了很久
\(\text{Code}\)
#include <cstdio>
#include <iostream>
#include <vector>
#define IN inline
using namespace std;
const int N = 1e5 + 5;
int n, m, h[N], tot, a[N];
struct edge{int to, nxt;}e[N * 2];
IN void add(int x, int y) {e[++tot] = edge{y, h[x]}, h[x] = tot;}
int dep[N], rt, size, used[N], son[N], sz[N], Rt, fa[N];
struct BIT {
vector <int> c;
IN void build(int n) {c.resize(n);}
IN int lowbit(int x) {return x & (-x);}
IN void add(int x, int v) {for(; x < c.size(); x += lowbit(x)) c[x] += v;}
IN int query(int x) {
if (x >= (int)c.size()) x = c.size() - 1;
int s = 0; for(; x > 0; x -= lowbit(x)) s += c[x]; return s;
}
}tr[N][2];
int rev[N * 2], st[N], dfc, lg[N * 2], mn[N * 2][21];
void dfs(int x, int dad) {
st[x] = ++dfc, rev[dfc] = x;
for(int i = h[x], v; i; i = e[i].nxt) {
if ((v = e[i].to) == dad) continue;
dep[v] = dep[x] + 1, dfs(v, x), rev[++dfc] = x;
}
}
IN int LCA(int x, int y) {
x = st[x], y = st[y]; if (x > y) swap(x, y);
int k = lg[y - x + 1];
if (dep[mn[x][k]] < dep[mn[y - (1 << k) + 1][k]]) return mn[x][k];
return mn[y - (1 << k) + 1][k];
}
IN int Dis(int x, int y) {return dep[x] + dep[y] - dep[LCA(x, y)] * 2;}
void getrt(int x, int dad) {
sz[x] = 1, son[x] = 0;
for(int i = h[x], v; i; i = e[i].nxt) {
if ((v = e[i].to) == dad || used[v]) continue;
getrt(v, x), sz[x] += sz[v], son[x] = max(son[x], sz[v]);
}
son[x] = max(son[x], size - sz[x]);
if (son[rt] > son[x]) rt = x;
}
void divide(int x) {
used[x] = 1, tr[x][0].build(size + 1), tr[x][1].build(size + 2);
for(int i = h[x], v; i; i = e[i].nxt) {
if (used[v = e[i].to]) continue;
rt = 0, size = sz[v], getrt(v, x), fa[rt] = x, divide(rt);
}
}
void obtain() {
lg[0] = -1;
for(int i = 1; i <= dfc; i++) mn[i][0] = rev[i], lg[i] = lg[i >> 1] + 1;
for(int i = 1; i <= lg[dfc]; i++) {
for(int j = 1; j + (1 << i) - 1 <= dfc; j++)
if (dep[mn[j][i - 1]] < dep[mn[j + (1 << i - 1)][i - 1]])
mn[j][i] = mn[j][i - 1]; else mn[j][i] = mn[j + (1 << i - 1)][i - 1];
}
for(int i = 1; i <= n; i++)
for(int j = i; j; j = fa[j]) {
tr[j][0].add(Dis(j, i) + 1, a[i]);
if (fa[j]) tr[j][1].add(Dis(fa[j], i) + 1, a[i]);
}
}
IN void read(int &x) {
x = 0; char ch = getchar(); int f = 1;
for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3)+(x<<1)+(ch^48), ch = getchar());
x *= f;
}
IN int Query(int x, int k) {
int ans = 0;
for(int i = x; i; i = fa[i]) {
ans += tr[i][0].query(k - Dis(i, x) + 1);
if (fa[i]) ans -= tr[i][1].query(k - Dis(fa[i], x) + 1);
}
return ans;
}
int main() {
read(n), read(m);
for(int i = 1; i <= n; i++) read(a[i]);
for(int i = 1, u, v; i < n; i++) read(u), read(v), add(u, v), add(v, u);
rt = 0, size = n, son[0] = 2e9, getrt(1, 0), Rt = rt, divide(rt), dfs(Rt, 0), obtain();
for(int op, x, y, lst = 0; m; --m) {
read(op), read(x), read(y), x ^= lst, y ^= lst;
if (op) {
for(int i = x; i; i = fa[i]) {
tr[i][0].add(Dis(x, i) + 1, y - a[x]);
if (fa[i]) tr[i][1].add(Dis(x, fa[i]) + 1, y - a[x]);
}
a[x] = y;
}
else printf("%d\n", lst = Query(x, y));
}
}
P6329 【模板】点分树 | 震波的更多相关文章
- 【题解】P6329 【模板】点分树 | 震波
题外话 (其实模板题没必要在这里水题解的--主要是想说这个qwq) 小常数的快乐.jpg 我也不知道我为啥常数特别小跑得飞快--不加快读就能在 luogu 的最优解上跑到 rank5 ( 说不定深夜提 ...
- P6329-[模板]点分树 | 震波
正题 题目链接:https://www.luogu.com.cn/problem/P6329 解题思路 给出\(n\)个点的一棵树,每个点有权值,有\(m\)次操作 修改一个点\(x\)的权值为\(y ...
- 一篇自己都看不懂的点分治&点分树学习笔记
淀粉质点分治可真是个好东西 Part A.点分治 众所周知,树上分治算法有$3$种:点分治.边分治.链分治(最后一个似乎就是树链剖分),它们名字的不同是由于分治方式的不同的.点分治,顾名思义,每一次选 ...
- 线段树练习 3&&P3372 【模板】线段树 1
题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述 Input Description 第一行一个正整数n,接下 ...
- 【洛谷3345_BZOJ3924】[ZJOI2015]幻想乡战略游戏(点分树)
大概有整整一个月没更博客了 -- 4 月为省选爆肝了一个月,最后压线进 B 队,也算给 NOIP2018 翻车到 316 分压线省一这个折磨了五个月的 debuff 画上了一个不算太差的句号.结果省选 ...
- 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解
什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...
- 洛谷P3372 【模板】线段树 1
P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交 讨论 题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷 ...
- 洛谷P3373 【模板】线段树 2
P3373 [模板]线段树 2 47通过 186提交 题目提供者HansBug 标签 难度提高+/省选- 提交 讨论 题解 最新讨论 为啥WA(TAT) 题目描述 如题,已知一个数列,你需要进行 ...
- hdu 3074 Multiply game(模板级线段树)
离机房关门还有十分钟,这点时间能干些什么?故作沉思地仰望星空,重新捋一下一天的学习进度,或者,砍掉一棵模板级线段树. 纯模板,就是把单点更新,区间求和改为单点更新,区间求积. 1A. #include ...
- Luogu3373【模板】线段树2
P3373[模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行 ...
随机推荐
- 【大数据面试】Flink 04:状态编程与容错机制、Table API、SQL、Flink CEP
六.状态编程与容错机制 1.状态介绍 (1)分类 流式计算分为无状态和有状态 无状态流针对每个独立事件输出结果,有状态流需要维护一个状态,并基于多个事件输出结果(当前事件+当前状态值) (2)有状态计 ...
- node-sass报错(Node Sass could not find a binding for your current environment)
解决方案:参考 https://stackoverflow.com/questions/37986800/node-sass-couldnt-find-a-binding-for-your-curre ...
- 图书管理系统、聚合函数、分组查询、F与Q查询
目录 图书管理系统 1.表设计 2.首页搭建.展示 书籍的添加 书籍编辑 书籍删除 聚合函数 Max Min Sum Count Avg 分组查询 按照表分组 按照字段分组 F与Q查询 F查询 Q查询 ...
- 二阶段目标检测网络-Cascade RCNN 详解
摘要 1,介绍 1.1,Faster RCNN 回顾 1.2,mismatch 问题 2,实验分析 2.1,改变IoU阈值对Detector性能的影响 2.2,提高IoU阈值的影响 2.3,和Iter ...
- 基于redis乐观锁实现并发排队 - 基于scrapy运行数量的控制
有个需求场景是这样的,使用redis控制scrapy运行的数量.当系统的后台设置为4时,只允许scapry启动4个任务,多余的任务则进行排队. 概况 最近做了一个django + scrapy + c ...
- “喜提”一个P2级故障—CMSGC太频繁,你知道这是什么鬼?
大家好,我是陶朱公Boy. 背景 今天跟大家分享一个前几天在线上碰到的一个GC故障- "CMSGC太频繁". 不知道大家看到这条告警内容后,是什么感触?我当时是一脸懵逼的,一万个为 ...
- 【WPF】自定义一个自删除的多功能ListBox
原文地址 https://www.cnblogs.com/younShieh/p/17008534.html 如果本文对你有所帮助,不妨点个关注和推荐呀,这是对笔者最大的支持~ 我需要一个ListBo ...
- 使用Git提交代码
目录 1.提交前准备工作 2.代码提交步骤 3.从git上面拉代码 4.Git变更集 5.参考资料 1.提交前准备工作 首先去git官网下载git工具(Git GUI Here.Git Bash He ...
- [LeetCode]最大连续1的个数
题目 代码 class Solution { public: int findMaxConsecutiveOnes(vector<int>& nums) { int length= ...
- MySQL优化四,高性能优化
一,查询优化器 这个部分的整个过程是由MySQL的存储引擎来做的,优化器就会根据存储引擎来使用原来的开销, 优化后的开销,哪个更好一点? 1.如果是查询语句(select语句),首先会查询缓存是否已有 ...