树链剖分入门+博客推荐
树链剖分入门博客推荐
网上关于树链剖分的文章很多,自己在学习树链剖分的时候找到了几篇好的文章,代码规范,有图例。树链剖分的部分自己先挖个坑,以后再专门写个博客来总结。
博客推荐
推荐理由:每个函数完成后的结果都有相应的图例,可以自己模拟一下和图对应,加深对函数功能的理解。
推荐理由:完整的函数实现,树链剖分+线段树的完整代码。
推荐理由:代码规范,通俗易懂。
我的常用代码模板
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+7;
struct node{
int l, r;
int ans, lazy;
}
struct edge{
int to, next;
}e[maxn<<1];
int head[maxn], len;
int son[maxn], size[maxn], dep[maxn], fa[maxn];
int top[maxn], inp[maxn], cnt;
void init()
{
len=cnt=0;
for(int i=0; i<=n; i++)
head[i]=-1;
}
void add(int u, int v)
{
e[len].to=v;
e[len].next=head[u];
head[u]=len++;
}
- dfs1主要是解决树上点的基本信息
void dfs1(int u, int f, int depth)
{
size[u]=1;
dep[u]=pedth;
fa[u]=f;
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v=e[i].to;
if(v==f) continue;
dfs1(v, u, depth+1);
size[u]+=size[v];
if(size[v] > size[son[u]])
son[u]=v;
}
}
- dfs2是处理dfs序和重链
void dfs2(int u, int tp)
{
top[u]=tp;
in[u]=++cnt;
if(!son[u])
return;
dfs2(son[u], tp);
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v=e[i].to;
if(v==son[u] || v==f[u])
continue;
dfs2(v, v);
}
}
- 处理x和y的最近公共祖先
//fx表示x所在链的顶,fy表示y所在链的顶。
void lca(int x, int y)
{
int fx=top[x], fy=top[y];
while(fx!=fy)
{
if(dep[fx] < dep[fy]) //确保每次更新都是深度大的都是x
{
swap(x, y);
swap(fx, fy);
}
x=fa[x];
fx=top[x];
}
return dep[x] < dep[y] ? x:y;
}
- 把从x到y的一条最短链上点的值改为z
//把从x到y的最近链上点的值改为z;
void update_chain(int x, int y, int z)
{
int fx=top[x], fy=top[y];
while(fx!=fy)
{
if(dep[fx] < dep[fy])
{
swap(x, y);
swap(fx, fy);
}
update(1, in[fx], in[x], z);
//每往上跳一次,就修改以次经过路径上的值,因为DFS序中id[fx] < id[x],所以是区间[id[fx],id[x]];
}
if(in[x] > id[y])
swap(x, y);
update(1, in[x], in[y], z);
}
- 求从x到y的最近一条链点值的总和。
int query_chain(int x, int y)
{
int ans=0, fx=top[x], fy=top[y];
while(fx!=fy)
{
if(dep[fx] < dep[fy])
{
swap(x, y);
swap(fx, fy);
}
ans+=query(1, in[fx], in[x]);
}
if(in[x] > in[y])
swap(x, y);
ans+=query(1, in[x], in[y]);
return ans;
}
欢迎评论交流!