​点击打开链接​

之前搞定的树链剖分专题,之前的状态持续萎靡,虽然现在仍旧是。不过总结什么的总得写一点的。

之前还有挺多东西,都想补补,不过现在实在是懒癌晚期,完全不想干,等寒假的时候再看看吧。


树链剖分,简单的说,其实就是把一棵树拆成很多条链,然后铺到一个区间里,这样就可以把树上的问题

转换成简单的区间问题,而区间问题我们可以用线段树和树状数组等等数据结构来维护。

其实,dfs序列就是一种树链剖分,因为dfs序列的连续一段在树上可以是一条链。

不过dfs序完全是乱来的,正常的树链剖分我们会选择节点最多的子树进行优先遍历,这样可以保证效率。

至于为啥,这个还是看论文去吧。


树链剖分能完成树上的修改和询问操作,包括一条链的修改,以及一个子树的修改。

void dfs(int x, int f)
{
ct[x] = 1; mx[x] = 0;
dep[x] = dep[f] + 1;
loop(i, ft[x], nt)
{
dfs(u[i], x);
ct[x] += ct[u[i]];
if (ct[u[i]] > ct[mx[x]]) mx[x] = u[i];
}
}

void Dfs(int x, int t)
{
top[x] = !t ? x : top[fa[x]];
L[x] = ++sz;
if (mx[x]) Dfs(mx[x], 1);
loop(i, ft[x], nt)
{
if (u[i] == mx[x]) continue;
Dfs(u[i], 0);
}
R[x] = sz;
}


上述的代码,就是两次dfs搞出一个dfs序列,这个序列就是树链剖分的结果了,

而这样搞定之后,[L[x],R[x]]就是x为根的子树,从L[x]到L[top[x]]就是从x开始到达重链的顶端。

剩下的就交给数据结构维护了。