dfs序七個經典問題

update-2018.07.23:  原文問題五思路描述有誤,已更正。數組

 參考自:《數據結構漫談》-許昊然數據結構

dfs序是樹在dfs先序遍歷時的序列,將樹形結構轉化成序列問題處理。3d

dfs有一個很好的性質:一棵子樹所在的位置處於一個連續區間中。blog

ps:deep[x]爲x的深度,l[x]爲dfs序中x的位置,r[x]爲dfs序中x子樹的結束位置get

1.點修改,子樹和查詢date

  在dfs序中,子樹處於一個連續區間中。因此這題能夠轉化爲:點修改,區間查詢。用樹狀數組或線段樹便可。遍歷

2.樹鏈修改,單點查詢im

  將一條樹鏈x,y上的全部點的權值加v。這個問題能夠等價爲:數據

  1).x到根節點的鏈上全部節點權值加v。查詢

  2).y到根節點的鏈上全部節點權值加v。

  3).lca(x,y)到根節點的鏈上全部節點權值和減v。

  4).fa(lca(x,y))到根節點的鏈上全部節點權值和減v。  

  上面四個操做能夠歸結爲:節點x到根節點鏈上全部節點的權值加減v。修改節點x權值,當且僅當y是x的祖先節點時,x對y的值有貢獻。

  因此節點y的權值能夠轉化爲節點y的子樹節點貢獻和。從貢獻和的角度想:這就是點修改,區間和查詢問題。

  修改樹鏈x,y等價於add(l[x],v),add(l[y],v),add(l[lca(x,y)],-v),add(l[fa(lca(x,y))],-v)。

  查詢:get_sum(r[x])-get_sum(l[x]-1)

  用樹狀數組或線段樹便可。

3.樹鏈修改,子樹和查詢

  樹鏈修改部分同上一問題。下面考慮子樹和查詢問題:前一問是從貢獻的角度想,子樹和同理。

  對於節點y其到根節點的權值和,考慮其子節點x的貢獻:w[x]*(deep[x]-deep[y]+1) = w[x]*(deep[x]+1)-w[x]*deep[y] 

  因此節點y的子樹和爲:

  

  ps:公式中的v[i]爲手誤,應爲w[i]。

  因此用兩個樹狀數組或線段樹便可:

    第一個維護∑w[i]*(deep[i]+1):支持操做單點修改,區間和查詢。(這也就是問題2)

    第二個維護∑ w[i]:支持操做單點修改,區間查詢。(這其實也是問題2)

4.單點更新,樹鏈和查詢

  樹鏈和查詢與樹鏈修改相似,樹鏈和(x,y)等於下面四個部分和相加:

  1).x到根節點的鏈上全部節點權值加。

  2).y到根節點的鏈上全部節點權值加。

  3).lca(x,y)到根節點的鏈上全部節點權值和的-1倍。

  4).fa(lca(x,y))到根節點的鏈上全部節點權值和的-1倍。

  因此問題轉化爲:查詢點x到根節點的鏈上的全部節點權值和。

  修改節點x權值,當且僅當y是x的子孫節點時,x對y的值有貢獻。

  差分前綴和,y的權值等於dfs中[1,l[y]]的區間和。

  單點修改:add(l[x],v),add(r[x]+1,-v);

5.子樹修改,單點查詢

  修改節點x的子樹權值,在dfs序上就是區間修改,單點權值查詢就是單點查詢。

  區間修改,單點查詢問題:樹狀數組或線段樹便可;

6.子樹修改,子樹和查詢

  題目等價與區間修改,區間查詢問題。用樹狀數組或線段樹便可。

7.子樹修改,樹鏈查詢

  樹鏈查詢同上,等價爲根節點到y節點的鏈上全部節點和問題。

  修改節點x的子樹權值,當且僅當y是x的子孫節點時(或y等於x),x對y的值有貢獻。

  x對根節點到y節點的鏈上全部節點和的貢獻爲:w[x]*(deep[y]-deep[x]+1)=w[x]*deep[y]-w[x]*(1-deep[x])

  同問題三,用兩個樹狀數組或線段樹便可。

相關文章
相關標籤/搜索