对于树上的信息,根据操作的不同,用不同的数据结构来维护,它们是相互独立的。如果有多种操作,分开维护最后加起来就行了。
目录
一、子树加,子树求和
【口胡】
可以利用dfs序。如果记录L[i]表示i号点的dfs序,R[i]表示i号点的子树搜索完后的dfs序那么x是y的祖先等价于:
L[y]∈ [L[x],R[x]]
dfs时用L数组记录dfn[x],当子树搜索完后,用R数组记录R[x].如下:
void dfs(int x,int fa){
L[x]=++sz;
for(int i=Head[x];i;i=Next[i])
if(V[i]!=fa)
dfs(V[i],x);
R[x]=sz;
}
这时要求子树和或子树加,用线段树维护就行了。
二、链加,单点求值
先上个模板题
描述
有n个节点N-1条边,这是一颗树,有2个操作:
1 x y v:表示将节点x到y最短路径上所有的点的权值+v
【链加】
2 x:表示查询节点x的权值
【单点求值】
开始的时候每个节点的权值是0
输入
第一行是数N,表示N个节点 接下来n-1行,每行描述了n-1条边。
接下来是一个数q表示有q次查询与询问 接下来q行,格式如题
输出
若干行
样例输入[复制]
3
1 2
2 3
3
1 1 2 5
1 1 3 2
2 2
样例输出[复制]
7
提示
n<=1e5 q<=1e5
【口胡】
对于一个链加,我们把它看做一个点到根的路径加:
这是一条从u到v的路径,g是u和v的最近公共祖先,在这条链上加C可以看做u到root加C,然后v到root加C,然后g到root减去2*C。但是这样g点的修改就被抵消,所以用一个额外的数组app记录当一个点为lca时修改的值。
我们修改时可以把修改放在u,v和g上(单点修改),查询时,我们就在这个点的子树中询问贡献(区间求和)。【因为一个点子树中的修改才对它有影响,其他地方的修改对它是没有贡献的】
这里用树状数组维护,支持单点修改和区间求和。【树状数组建立在DFS序上。】
假设我们查询一个点x,它的子树中有若干个修改,链1,链2,链3,链4.
对于链1,链2,链3,它们穿过了x,查询x的子树时就会把点1,点2,点3的贡献计入x中。
对于链4,虽然它在x的子树中