1. 程式人生 > >字首和與差分

字首和與差分

數列的字首和: 
sum[i]表示a[1]~a[i]的和 
用處1:求i~j的和sum[j]-sum[i-1] 
用處2:區間修改。設定一個change陣列。當區間[i,j]上要加k時,我們令change[i]+=k,令change[j+1]-=k。如果我們對change陣列求字首和的話,字首和sum_change[i]就是i這個位置變動的值

樹的字首和有兩種 
– 根路徑字首和sum2[i],指i到根節點所有節點的權值之和。 
– 子樹字首和sum1[i],指i的子樹(包括i本身)所有節點的權值之和。

樹的字首和用處 
根路徑字首和,可以用來求路徑節點權值和(配合lca食用) 
–假如要求x到y路徑的權值和,x,y的lca是z。則可以用sum[x]+sum[y]-2sum[z]+value[z] 
子樹字首和

,可以用來做路徑修改(也得配合lca食用) 
–設定一個修改陣列change。如果要對x到y路徑上的所有點權值+k,lca為z。那麼change[x]+=k,change[y]+=k,change[z]-=k,change[fa[z]]-=k。這樣如果最後對change[i]求字首和的話,最後得到的結果就是i權值的修改量 
–特點:可以O(1)修改,但是隻能一次查詢(因為要求字首和O(n))

字首和的使用不都是用來差分的? 
二維陣列的差分:Ans=sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1] 
二維陣列的修改:用陣列C存修改資訊。在C[x1][y1]處加上a,在C[x2+1][y1]和C[x1][y2+1]處減a,在C[x2+1][y2+1]再加上a。 
最後(i,k)位置上變化的數值就是C陣列在(i,k)位置的字首和。 
基本就是 
這裡寫圖片描述

樹上差分經典思路 
①利用dfs序的時間戳,一個點拆成兩個點,每次在in+1,在out-1,然後bit統計字首和,資瓷動態修改和查詢子樹訪問次數。用於子樹打標記。 
②對於點x,y設r=lca(x,y)。在x+1,y+1,r-2,然後從所有葉節點往上累加。用於樹鏈打標記,資瓷查詢某條邊的訪問次數。 
③對於點x,y設r=lca(x,y)。在x+1,y+1,r-1,father[r]-1,然後從所有葉節點往上累加。用於樹鏈打標記,資瓷查詢某個點的訪問次數。