dfs序七个经典问题 ——weeping
本博文又名:手把手教你写树状数组
单点修改,区间查询
维护每个点的权值:
1. 修改 x (增加 w ):单点修改——add(x,w);
2. 查询 x 的子树:区间查询——ans=query(le[x])-query(ri[x]-1);
首先将 u−v 树链和查询转化成 u−root,v−root,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);
)
树链修改的道理同上,等价于修改某个点到 root 的路径的权值和。
考虑修改的树链的一个端点为 x ,增加值为 w ,影响到的则是 x 到 root 的路径上的点的权值,即当且仅当 x 在 y 的子树内,修改 x 会对 y 的权值造成影响,增加值为 w 。
对于点 y 而言,其权值的变化量事实上就是其子树中点权值的变化量之和(相当于把 y 的变化量记在了其子孙节点的头上),即 ∑x∈y的子树w[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);
树链修改的道理同上,等价于修改某个点到 root 的路径的权值和。
考虑修改的树链的一个端点为 x ,影响到的则是 x 到 root 的路径上的点的权值,即当且仅当 x 在 y 的子树内,修改 x 会对 y 的子树和造成影响,增加值为 w[x]∗(depth[x]−depth[y]+1) 。
y 的变化量总和则为
开两个树状数组,分别维护 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));
区间修改,单点查询
前缀和维护点权值的变化量:
1. 修改 x 的子树(增加 w ):区间修改——add(le[x],w),add(ri[x]+1,-w);
2. 查询 x :单点查询——ans=x的初始值+query(le[x]);
区间修改,区间查询
维护每个点的权值
1. 修改 x 的子树(增加 w ):区间修改——add(1,le[x],ri[x],w);
2. 查询 x 的子树:区间查询——ans=query(1,le[x],ri[x]);
具体见【小结】树状数组的区间修改与区间查询 ——MoeO3,本菜就不多废话了_(:3」∠)_
(已经赤果果地变成一篇树状数组的文章啦(逃
树链修改的道理同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)
)
完结撒花~
哪里有错误还烦请批评指正啦