dfs序基本类型 详细

参考

dfs序七个经典问题 ——weeping

本博文又名:手把手教你写树状数组

1. 单点修改,子树和查询

单点修改,区间查询

树状数组

维护每个点的权值:
1. 修改 x (增加 w ):单点修改——add(x,w);
2. 查询 x 的子树:区间查询——ans=query(le[x])-query(ri[x]-1);

2. 单点修改,树链和查询

首先将 uv 树链和查询转化成 uroot,vroot,lca(u,v)root,fa(lca(u,v))root 的查询,即要维护树上节点到 root 的权值和。
考虑修改点 x ,影响到的即为 x 的子树内的点到 root 的权值,所以,单点修改事实上是区间修改
至于查询,则是四个单点查询

线段树

维护每个节点到 root 的权值和:
1. 修改 x (增加 w ):区间修改——修改 [le[x],ri[x]] 区间,modify(1,le[x],ri[x],w);
2. 查询 [u,v] 链:单点查询——查询 u,v,lca(u,v),fa(lca(u,v))
ans=query(1,u)+query(1,v)-query(1,lca(u,v))-query(1,fa(lca(u,v)));
(本质上即四次查询 x query(1, x);

树状数组

前缀和维护点到 root 的权值和的变化量:
1. 修改 x (增加 w ):区间修改——add(le[x],w),add(ri[x]+1,-w);
2. 查询 [u,v] 链:单点查询——ans=[u,v]间权值和的初始值+query(le[u])+query(le[v])-query(le[lca(u,v)])-query(le[fa(lca(u,v))]);
(本质上即四次查询 x query(x);

3. 树链修改,单点查询

树链修改的道理同上,等价于修改某个点到 root 的路径的权值和。
考虑修改的树链的一个端点为 x ,增加值为 w ,影响到的则是 x root 的路径上的点的权值,即当且仅当 x y 的子树内,修改 x 会对 y 的权值造成影响,增加值为 w
对于点 y 而言,其权值的变化量事实上就是其子树中点权值的变化量之和(相当于把 y 的变化量记在了其子孙节点的头上),即 xyw[x] ,故为区间查询。而维护的即为子树中点权值的变化量,即单点修改

树状数组

维护每个点权值的变化量:
1. 修改 [u,v] 链(增加 w ):单点修改——add(u,w),add(v,w),add(lca(u,v),-w),add(fa(lca(u,v)),-w);
(本质上即四次修改 x add(x,w);
2. 查询 x :区间查询——ans=x的初始值+query(ri[x])-query(le[x]-1);

4. 树链修改,子树和查询

树链修改的道理同上,等价于修改某个点到 root 的路径的权值和。
考虑修改的树链的一个端点为 x ,影响到的则是 x root 的路径上的点的权值,即当且仅当 x y 的子树内,修改 x 会对 y 的子树和造成影响,增加值为 w[x](depth[x]depth[y]+1)
y 的变化量总和则为

xyw[x](depth[x]depth[y]+1)=xyw[x](depth[x]+1)depth[y]xyw[x]

仍是 单点修改,区间查询

树状数组

开两个树状数组,分别维护 w[x](depth[x]+1) w[x] .
1. 修改 [u,v] 链(增加 w ):单点修改——
add1(u,w*(depth[u]+1)),add1(v,w*(depth[v]+1)),add1(lca(u,v),-w*(depth[lca(u,v)]+1)),add1(fa(lca(u,v)),-w*(depth[fa(lca(u,v)]+1);
add2(u,w),add2(v,w),add2(lca(u,v),-w),add2(fa(lca(u,v)),-w);
(本质上即八次修改 x add(x,w);
2. 查询 x 的子树:区间查询——
ans=子树和的初始值+query1(ri[x])-query1(le[x]-1)-depth[x]*(query2(ri[x])-query2(le[x]-1));

5. 子树修改,单点查询

区间修改,单点查询

树状数组

前缀和维护点权值的变化量:
1. 修改 x 的子树(增加 w ):区间修改——add(le[x],w),add(ri[x]+1,-w);
2. 查询 x :单点查询——ans=x的初始值+query(le[x]);

6. 子树修改,子树和查询

区间修改,区间查询

线段树

维护每个点的权值
1. 修改 x 的子树(增加 w ):区间修改——add(1,le[x],ri[x],w);
2. 查询 x 的子树:区间查询——ans=query(1,le[x],ri[x]);

树状数组

具体见【小结】树状数组的区间修改与区间查询 ——MoeO3,本菜就不多废话了_(:3」∠)_
(已经赤果果地变成一篇树状数组的文章啦(逃

7. 子树修改,树链和查询

树链修改的道理同2. 3. 4. ,等价于修改某个点到 root 的路径的权值和。
考虑修改 x 的子树,影响的则是 x 的子树内的点到 root 的路径的权值和,即当且仅当 y x 的子树内,修改会对 y 的查询造成影响,增加值为 w[x](depth[y]depth[x]+1) 。故为区间修改,单点查询

树状数组

开两个树状数组,分别维护 w[x](depth[x]+1) w[x] .
1. 修改 x 的子树(增加 w ):区间修改——
add1(le[x],w[x]*(-depth[x]+1);add1(ri[x]+1,-w[x]*(-depth[x]+1);
add2(le[x],w[x]);add2(ri[x]+1,-w[x]);
2. 查询 [u,v] 链:单点查询——
ans=[u,v]间权值和的初始值+(query1(le[u])+query1(le[v])-query1(le[lca(u,v)])-query1(le[fa(lca(u,v))]))+depth[y]*(query2(le[u])+query2(le[v])-query2(le[lca(u,v)])-query2(le[fa(lca(u,v))]));
(本质上即八次查询 x query(x)

完结撒花~
哪里有错误还烦请批评指正啦

你可能感兴趣的:(dfs,树状数组)