树链剖分

树链剖分小结

荒凉一梦 提交于 2019-11-26 22:45:25
什么是树链剖分 树链剖分,计算机术语,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组、 \(BST\) 、 \(SPLAY\) 、线段树等)来维护每一条链。——百度百科 树链剖分就是维护轻、重链,然后用其他数据结构来维护。(一般用树状数组或线段树) 概念 重儿子:所有儿子中siz最大的结点 轻儿子:除了重儿子以外的儿子 (强调:一个节点出了重儿子以外的点 都是 轻儿子) 重边:与重儿子连成的边 轻边:与轻儿子连成的边 重链:由多条重边连接而成的路径 轻链:由多条轻边连接而成的路径(一般都只有一条) 设的变量 \(fa[x]\) , \(x\) 的父亲 \(dep[x]\) , \(x\) 的深度 \(siz[x]\) , \(x\) 的子树大小 \(son[x]\) , \(x\) 的重儿子 \(dfn[x]\) , \(x\) 的新的编号(做 \(dfs\) 的顺序) \(top[x]\) , \(x\) 所在的重链的顶端节点 (强调:我们可以保证每个节点都在也只在一条重链里) \(rk[x]\) , \(dfn[]\) 为 \(x\) 的在树中的节点 步骤 一般是两遍 \(dfs\) 。 第一遍:求出 \(fa[],dep[],siz[],son[]\) void dfs(int x) { dep[x] =

最近目标2333

故事扮演 提交于 2019-11-26 21:03:18
最近目标 并查集: P2024 [NOI2001]食物链 P1525 关押罪犯 (二分+二分图)(并查集代表监狱)(并查集代表犯人之间的关系) 动态规划dp: P2016 战略游戏 P1352 没有上司的舞会   P1273 有线电视网 P3354 [IOI2005]Riv 河流 P3140 [USACO16FEB]再探圆形谷仓Circular Barn R… P3112 [USACO14DEC]后卫马克Guard Mark P3092 [USACO13NOV]没有找零No Change P2967 [USACO09DEC]视频游戏的麻烦Video Game Troubles P3116 [USACO15JAN]约会时间Meeting Time P3509 [POI2010]ZAB-Frog 树上dp: 洞窟探索 P2015 二叉苹果树 P2014 选课 二分: T8662 吃桃子 树链剖分 : P3178 [HAOI2015]树上操作 P3384 【模板】树链剖分 P1600 天天爱跑步    二叉排序树: P1908 逆序对 图论: P3385 【模板】负环 贪心/暴力: P3745 [六省联考2017]期末考试 P3621 [APIO2007]风铃 哈希,hash: P3538 [POI2012]OKR-A Horrible Poem 我也不知道是什么233(我太弱了:

树链剖分

三世轮回 提交于 2019-11-26 20:49:05
树链剖分 一般用来求树上区间查询、修改 或 求LCA 学习 树链剖分 之前要学会 线段树 树链剖分 需 线段树 维护 首先弄清几个名字 重儿子 所有儿子中,子树大小最大那个儿子 轻儿子 除重儿子以外的儿子 重边 连接重儿子的边 轻边 连接轻儿子的边 重链 由重边组成的路径 轻链 由轻边组成的路径 举个例子: 剖分过程要计算的值 father[i] i在树中的父亲 d[i] i在树中的深度 size[i] i的子树大小 son[i] i的重儿子 top[i] i在的重路径的顶部 seq[i] i结点在线段树中的位置 rev[i] 线段树的第i个位置在树中的位置 预处理 两遍dfs 第一遍dfs求出前四个值 void dfs1(int u,int fa) { father[u]=fa; d[u]=d[fa]+1; size[u]=1; for (int i=h[u];i!=0;i=e[i].next) { int v=e[i].to; if (v==fa) continue; dfs1(v,u); size[u]+=size[v];//累加字数个数 if (size[v]>size[son[u]]) son[u]=v;//存下重儿子 } } 第二遍dfs求出后三个值 void dfs2(int u,int fa) { if (son[u]) { seg[son[u]]=++cnt;/

浅谈树链剖分

邮差的信 提交于 2019-11-26 20:34:05
目录 什么是树链剖分? 类似 为什么要学树链剖分? 少废话,正题如下: 轻儿子&重儿子 我们需要维护什么? CODE: 人工栈CODE: 操作: 建树 CODE: 人工栈CODE: 查询 LCA查询 CODE: 区间极值或和查询 CODE: 基本知识讲完了,重在理解,你明白了吗? 【NOIP2013提高组day1】货车运输 Description Input Output Sample Input Sample Output Data Constraint 好,讲正解: CODE: 再推荐几道例题: 树的统计CODE: Solution CODE: @ 什么是树链剖分? 指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组、SBT、SPLAY、线段树等)来维护每一条链,主要用来维护树上每条链的极值或和之类的。 类似 首先把树上倍增摆在前面,如果不会树上倍增就不必来看树链剖分。 为什么要学树链剖分? 有的人说:“我会树上倍增,我怕谁?”,没错,你怕的就是树链剖分。 意思是:树上倍增能做的,树链剖分都能做;树链剖分能做的,树上倍增不一定能做。树上倍增虽然能求树上区间极值或和,但一旦有树上边或点权值修改的操作,您就死翘翘了~这时我们需要一个新的算法来补上我们的树上倍增操作的漏洞,没错,就是 树链剖分 !没错

树链剖分

自闭症网瘾萝莉.ら 提交于 2019-11-26 20:25:51
入门博客推荐 树链剖分说白了就是 把一棵树拆成若干个不相交的链,然后用一些数据结构去维护这些链。 因为通常的数据结构处理区间信息很容易,但处理树上的信息就显得捉襟见肘了。于是我们想到把树拍成一个区间用线段树去维护信息。(和树的dfs序是类似的原理)。 树链剖分的几个常见应用: ①查询/修改树的子树的值:因为dfs的遍历顺序关系,每颗子树在线段树上必定是一段连续的区间,所以容易处理。 ②查询/修改树两点路径间的值:因为每条重链是一段连续区间,那么两点间路径肯定是若干条链合起来得到,也就是线段树上的几段区间。 https://www.luogu.org/problem/P3384 #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <algorithm> #include <cstdlib> #include <vector> #include <stack> #include <map> #include <string> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 2e5 + 10; int f[maxn];//f

[树链剖分][树状数组] Luogu P3676 小清新数据结构题

偶尔善良 提交于 2019-11-26 17:35:09
题目描述 在很久很久以前,有一棵n个点的树,每个点有一个点权。 现在有q次操作,每次操作是修改一个点的点权或指定一个点,询问以这个点为根时每棵子树点权和的平方和。 (题目不是很好懂,没看太懂的可以看看样例解释) 题解 大爷博客( 戳我 ) 代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define ll long long 5 #define sqr(x) (x)*(x) 6 using namespace std; 7 const ll N=2e5+10; 8 struct edge{ll from,to;}e[N<<1]; 9 ll n,m,cnt,ans,tot,w[N],c[N],fa[N],sz[N],id[N],pos[N],deep[N],son[N],top[N],head[N],sz1[N],sz2[N]; 10 void add(ll x,ll y) { for (int i=x;i<=n;i+=i&(-i)) sz1[i]+=y,sz2[i]+=x*y; } 11 ll query(ll x) { ll r=0; for (ll i=x;i;i-=i&(-i)) r+=(x+1)*sz1[i]-sz2[i]; return r; } 12 void insert(ll

树链剖分 树剖求lca 学习笔记

谁都会走 提交于 2019-11-26 12:45:46
树链剖分 顾名思义,就是把一课时分成若干条链,使得它可以用数据结构(例如线段树)来维护 一些定义: 重儿子:子树最大的儿子 轻儿子:除了重儿子以外的儿子 重边:父节点与重儿子组成的边 轻边:除重边以外的边 重链:重边连接而成的链 轻链:轻边连接而成的链 链头:一条链上深度最小的点 第一步:进行进行轻重边的划分。 定义size[x]为以x为根的子树节点个数,令v为u儿子中size值对打的节点,那么(u,v)就是重边,其它出边都是轻边 两个重要性质: 1.轻边(u,v)中,Size[v]<size[u]/2 显然,如果儿子v的size>=size[u],则它应该是重边,u的子树中没有size比他更大的 (作者考试爆零去了,一会再写) 来源: https://www.cnblogs.com/lzy-blog/p/11320613.html