【学习笔记】点分树
【学习笔记】点分树
点分树是一种动态维护树上信息的高级数据结构,就是在点分治的基础上支持在线修改操作,所以很多人也很喜欢叫它动态点分治。个人觉得非常暴力。
我们借助 【模板】点分树 | 震波 这道题来深入理解点分树的思想和实现过程。
友情提示:本题中较难理解的部分其实是 点分树上维护线段树,但纯粹的点分树只有建树部分!要想更容易地理解,建议先完成 P4178 Tree ,这是本题的弱化版,不带修,就是个点分治+线段树。
代码详解
点分树的过程:
-
建立点分树
- 找整棵树的重心u
- 从u进入,找各子树的重心v,并给u,v连边
- 第2步的同时给点分树上每个节点都建一棵动态开点线段树。
- 建立点分树上距离和实际距离之间的映射关系
-
修改和查询
-
与 x 相关的每一棵线段树都需要在对应处修改。
-
时刻记住sg和ch的定义:
: 在点分树上,以 为根的子树中(刚好包括了原树上以 为重心的子树的所有点),到 距离为 的所有点的权值之和。 : 在点分树上,以 为根的子树中(刚好包括了原树上以 为重心的子树的所有点),到 距离为 的所有点的权值之和。( 是 在点分树上的父亲)
-
一些犯过的错误:
- lca 不初始化,倍增不初始化(不适应大码量导致的)
- 点分树上修改查询,跳父节点的时候距离写成
而不是 。 - 找重心时,不初始化最大连通块
。 - 距离映射的时候for循环时
for(int i = x; i; i = fa[i])
,修查的时候for循环是for(int i = x; fa[i]; i = fa[i])
,并且其实修查的“研究对象”都是fa[i]
不是i
,所以d = dis[x][ dep[x] - dep[fa[i]] ]
而不是d = dis[x][ dep[x] - dep[i] ]
。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=(r);++i)
#define G(i,r,l) for(int i(r);i>=(l);--i)
using namespace std;
using ll = long long;
const int N = 2e5 + 5;
struct node{
int v, ne;
}e[N << 1];
int first[N], idx = 0;
int n, m, w[N];
void add(int x, int y){
e[++ idx] = (node){y, first[x]};
first[x] = idx;
}
struct LCA{
int dep[N], fa[N][20];
void ini(int u, int f){
dep[u] = dep[f] + 1;
fa[u][0] = f;
F(i, 1, 19) fa[u][i] = fa[fa[u][i - 1]][i - 1];
for(int i = first[u]; i; i = e[i].ne){
int v = e[i].v;
if(v == f) continue;
ini(v, u);
}
}
int getlca(int x, int y){
if(dep[x] < dep[y]) swap(x, y);
G(i, 19, 0) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if(x == y) return x;
G(i, 19, 0) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
int getdis(int x, int y){
return dep[x] + dep[y] - 2 * dep[getlca(x, y)];
}
}lca;
struct segtree{
int cnt = 0, root[N], sum[N * 40], lc[N * 40], rc[N * 40];
void update(int &u, int l, int r, int x, int y){
if(!u) u = ++ cnt;
if(l == r){
sum[u] += y;
return ;
}
int mid = (l + r) >> 1;
if(x <= mid) update(lc[u], l, mid, x, y);
else update(rc[u], mid + 1, r, x, y);
sum[u] = sum[lc[u]] + sum[rc[u]];
}
int query(int u, int l, int r, int x, int y){
if(!u) return 0;
if(l >= x && r <= y) return sum[u];
int mid = (l + r) >> 1, ret = 0;
if(x <= mid) ret += query(lc[u], l, mid, x, y);
if(y > mid) ret += query(rc[u], mid + 1, r, x, y);
return ret;
}
}sg, ch;
struct PointTree{
int sum, root, mxp[N], siz[N], fa[N], dep[N], dis[N][20];
bool del[N];
void dfs(int u, int f){
siz[u] = 1;
mxp[u] = 0;
for(int i = first[u]; i; i = e[i].ne){
int v = e[i].v;
if(v == f || del[v]) continue;
dfs(v, u);
siz[u] += siz[v];
mxp[u] = max(mxp[u], siz[v]);
}
mxp[u] = max(mxp[u], sum - siz[u]);
if(mxp[u] < mxp[root]) root = u;
}
void getroot(int u, int size){
mxp[root = 0] = sum = size;
dfs(u, 0);
dfs(root, 0);
}
void bus(int u, int f, int wc, int d){
sg.update(sg.root[wc], 0, n, d, w[u]);
for(int i = first[u]; i; i = e[i].ne){
int v = e[i].v;
if(v == f || del[v]) continue;
bus(v, u, wc, d + 1);
}
}
void buc(int u, int f, int wc, int d){
ch.update(ch.root[wc], 0, n, d, w[u]);
for(int i = first[u]; i; i = e[i].ne){
int v = e[i].v;
if(v == f || del[v]) continue;
buc(v, u, wc, d + 1);
}
}
void build(int u){
del[u] = 1;
bus(u, 0, u, 0);
for(int i = first[u]; i; i = e[i].ne){
int v = e[i].v;
if(del[v]) continue;
getroot(v, siz[v]);
dep[root] = dep[u] + 1;
fa[root] = u;
buc(v, u, root, 1);
build(root);
}
}
void init(){
getroot(1, n);
build(root);
lca.ini(root, 0);
F(i, 1, n) for(int j = i; j; j = fa[j]) dis[i][ dep[i] - dep[j] ] = lca.getdis(i, j);
}
void update(int x, int y){
sg.update(sg.root[x], 0, n, 0, y - w[x]);
for(int i = x; fa[i]; i = fa[i]){
int d = dis[x][ dep[x] - dep[fa[i]] ];
sg.update(sg.root[fa[i]], 0, n, d, y - w[x]);
ch.update(ch.root[i], 0, n, d, y - w[x]);
}
}
int query(int x, int y){
int ret = sg.query(sg.root[x], 0, n, 0, y);
for(int i = x; fa[i]; i = fa[i]){
int d = dis[x][ dep[x] - dep[fa[i]] ];
ret += sg.query(sg.root[fa[i]], 0, n, 0, y - d);
ret -= ch.query(ch.root[i], 0, n, 0, y - d);
}
return ret;
}
}pt;
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
F(i, 1, n) cin >> w[i];
F(i, 1, n - 1){
int u, v;
cin >> u >> v;
add(u, v);
add(v, u);
}
pt.init();
int las = 0;
while(m --){
int op, x, y;
cin >> op >> x >> y;
x ^= las;
y ^= las;
if(op == 0) las = pt.query(x, y), cout << las << '\n';
else pt.update(x, y), w[x] = y;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具