首页 > 其他分享 >树链剖分

树链剖分

时间:2024-05-02 17:11:37浏览次数:21  
标签:剖分 int top cin 树链 dep dfn ql

树链剖分,简称树剖,就是把一颗又大又高的树拆成一些链,方便使用某些数据结构。

一般树剖

我们随便 DFS 一下,将整棵树分成一些链,其中里面的 DFS 序连续。

链的数量不管怎样是固定的 \(O(N)\)。

hack:

hack.bmp

某种 DFS 序是 \((1,3,2,5,4,7,6,9,8,11,10)\),只要你不走运刚好,就仍然可以把单次询问卡到 \(O(N)\)。

所以我们要把这坨东西优化一下。

重链优先

DFS 时优先用子树大小大的,剩下的随便。

链的数量没改进,但是单次询问的复杂度降低到 \(O(\log N)\)(因为只会有 \(O(\log N)\) 个轻边)。

证明:

考虑从某个节点往根节点走,路上遇到的边全是轻边。

很显然往上面每多一个轻边节点数量就会多一倍。

然后你就可以用这种方式把树打成一条链然后在链上写东西了(说实话你可以把树打成链后在链上跑莫队,但是这既没有必要也不是很好)。

同时我们注意到这个玩意还满足普通 DFS 的性质,所以仍然支持子树修改/查询的操作。

这个玩意也可以求 \(\operatorname{LCA}\):

  1. 如果两个节点在同一个链里面,深度小的就是 \(\operatorname{LCA}\)。

  2. 否则,第一个节点的链的顶端的深度大,将第一个节点跳至链的顶端的父亲,否则第二个节点跳至链的顶端的父亲,然后返回第一步。

既然能求 \(\operatorname{LCA}\),那么也能处理链上修改/查询。

于是就有了下面这道题。

P3384 【模板】重链剖分/树链剖分

一棵 \(N\) 个节点的树,每一个节点有一个点权 \(V_i\)。

四个操作:

链上点的点权加一个数,

查询链上的点权和,

子树点权加一个数,

查询子树点权和。

直接把树打成一个链,然后链上随便写一个线段树维护。

很难写。

代码 ```cpp #include #define int long long using namespace std;

int n, m, r, p, a, b, op, x, y, z;
int d[400040], t[400040], c[100010];
int fa[200020], dfn[200020], ss[200020], dep[200020], top[200020], hv[200020], dcnt, ed[200020];
vector to[200020];

void pushdn(int x, int l, int r) {
int mid = (l + r) >> 1;
d[x * 2] += (mid - l + 1) * t[x];
d[x * 2 + 1] += (r - mid) * t[x];
t[x * 2] += t[x], t[x * 2 + 1] += t[x];
t[x] = 0;
}

int query(int x, int l, int r, int ql, int qr) {
if(r < ql || qr < l) {
return 0;
}
if(ql <= l && r <= qr) {
return d[x];
}
pushdn(x, l, r);
int mid = (l + r) >> 1;
return query(x * 2, l, mid, ql, qr) + query(x * 2 + 1, mid + 1, r, ql, qr);
}

void add(int x, int l, int r, int ql, int qr, int v) {
if(r < ql || qr < l) {
return ;
}
if(ql <= l && r <= qr) {
d[x] += (r - l + 1) * v;
t[x] += v;
return ;
}
pushdn(x, l, r);
int mid = (l + r) >> 1;
add(x * 2, l, mid, ql, qr, v);
add(x * 2 + 1, mid + 1, r, ql, qr, v);
d[x] = d[x * 2] + d[x * 2 + 1];
}

void DFS(int x) {
ss[x] = 1;
dep[x] = dep[fa[x]] + 1;
for(auto i : to[x]) {
if(i != fa[x]) {
fa[i] = x;
DFS(i);
ss[x] += ss[i];
if(ss[i] > ss[hv[x]]) {
hv[x] = i;
}
}
}
}

void HCD(int x) {
dfn[x] = ++dcnt;
ed[x] = dfn[x];
add(1, 1, n, dfn[x], dfn[x], c[x]);
if(hv[x]) {
top[hv[x]] = top[x];
HCD(hv[x]);
ed[x] = ed[hv[x]];
}
for(auto i : to[x]) {
if(i != fa[x] && i != hv[x]) {
top[i] = i;
HCD(i);
ed[x] = ed[i];
}
}
}

int LCA(int x, int y) {
int ans = 0;
for(; top[x] != top[y]

标签:剖分,int,top,cin,树链,dep,dfn,ql
From: https://www.cnblogs.com/leavenothingafterblog/p/18170315

相关文章

  • 重链剖分题目选讲
    染色给定一棵\(n\)个节点的无根树,共有\(m\)个操作,操作分为两种:将节点\(a\)到节点\(b\)的路径上的所有点(包括\(a\)和\(b\))都染成颜色\(c\)。询问节点\(a\)到节点\(b\)的路径上的颜色段数量。颜色段的定义是极长的连续相同颜色被认为是一段。例如112221由......
  • 树链剖分
    link1link2前言:树链剖分实际上就是一种将树形结构剖分成一条条链状结构,并用线性数据结构来快速维护信息。重链剖分:一些定义:重儿子:一个节点的重儿子定义为它的子节点中子树节点最大的节点。轻儿子:一个节点除重儿子外的所有儿子重边:一个节点到它的重儿子的边即为重边......
  • 树链剖分
    参考链接:https://www.cnblogs.com/dx123/p/16320467.html(感谢董晓老师)树链剖分求LCA比倍增快一些https://www.luogu.com.cn/problem/P3379#include<bits/stdc++.h>constintN=5e5+5;usingnamespacestd;intn,m,root;inth[N],ne[2*N],e[2*N],idx;intdep[N]......
  • 树链剖分lca笔记
    树链剖分求lca参考资料:https://www.cnblogs.com/cangT-Tlan/p/8846408.html[树链剖分lca]大佬讲的很清楚%%%orz这篇博客是我的学习笔记。树链剖分:树链剖分,计算机术语,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结......
  • 「树链剖分」 学习笔记
    一,树链剖分的思想与概述正如其名,树链剖分用于将树剖分成若干条链的形式,以维护树上路径的信息,其中剖分出的链有多种形式,最常见的是重链,还有长链或更多其它的链。其中剖分出的链为重链时,就引出了下文的主角「重链剖分」。重链剖分能保证划分出的每条重链上的节点DFS序连续,因此......
  • 树链剖分 学习笔记
    随便写一点。1.原理定义重儿子为子树内子树大小最大的任一个点,重边为重儿子向其父亲连的边,其余为轻边。根据定义,轻边的父亲的子树大小一定不小于这个点的子树大小的二倍。又可以证出重边数量是\(O(\logn)\)的。因此可以用线段树维护这个东西。2.应用2.1dsu2.2lca考......
  • 【学习笔记】树链剖分
    一、重链剖分1.定义&作用树链剖分用于解决在树上执行的操作,将树上操作变为区间操作。用区间来维护。2.主要思想&实现有一棵树然后,我们把边区分一下,有一些边是“重边”,其余的是“轻边”,像这样:(红边为重边,黑边为轻)重边和轻边如何确定呢?看每一个结点旁的红色数字,代表他......
  • 1039. 多边形三角剖分的最低得分
    题目链接:实现一、记忆化搜索classSolution{public:intminScoreTriangulation(vector<int>&values){intn=values.size();intmemo[n][n];memset(memo,-1,sizeofmemo);//-1表示还没有计算过function<int(int,int)>df......
  • 重链剖分学习笔记
    Part.1引入重链剖分是一种用于解决树上的路径查询和修改问题的算法,他能将\(O(n)\)级别的操作转换为\(O(\logn)\)的级别,可以说十分常用。本文将带你深入解析这个算法。Part.2概念和思路在讲解本算法之前,我们先引入一些概念:轻重儿子:对于一个树上的节点\(u\),其儿子中子......
  • 树链剖分
    前言打算好好写一篇文章。至于为什么选了树剖这个主题,一是因为不久前学了长剖求树上k级祖先,二是因为重剖是我进提前批以来第一个学习到的树上算法,再加上有学弟写的超级详细的树剖学习笔记,也会使我写起来比较轻松一点。同时也可以熟悉一下TikZ这个宏包,它的功能实在是太多了,......