差分學習筆記

June_Failure發表於2024-04-07

差分

(姍姍來遲的一篇學習筆記)

Part 1 一維差分

P2367 語文成績

給出一個序列,支援修改,查詢最小值。

在不考慮資料結構的情況下,有一種東西,叫差分。

他可以做到 \(O(1)\) 修改,\(O(n)\) 查詢。

首先假設有一個序列:\(1,6,8,5,10\)

他的差分陣列就是:\(1,5,2,-3,5\)\(d_i=a_i-a_{i-1}\)

如果是要對區間 \([l,r]\) 加上某個數 \(x\) 的話,只要在把 \(d[l]\) 加上 \(x\)\(d[r+1]\) 減去 \(x\) 即可。

原因就是,在修改完以後,我們需要遍歷一次序列去更新新的 \(a_i\)\(a_i=a_{i-1}+d[i]\),假設 \(x\) 修改了 \([l,r]\)\(a_{l+1}\) 就必然加上 \(x\),由於 \(d_{l+2}\) 並沒有改變,也就是相差的數不變。加上這個數,\(a_{l+2}\) 一樣會更新。但是到了 \(a_{r+1}\) 我們就不必加了,所以要減去 \(x\)

\(Code\)

P1083 借教室

題目裡邊藏了很多細節,稍不注意到就會錯過正解。

  1. 一旦遇到第一個不滿足的,就直接停止分配。

  2. 按照先後順序來借。先到先得。

看到第二個性質,不難想到二分查詢來判斷是否滿足條件。

而對於從 \([l,r]\) 中借教室,可以使用差分輕鬆實現。差分陣列儲存的是每天的借的教室個數。

而二分的判斷閉區間,就是對於 \([1,l]\) 是否可以滿足借的原則來進行的一個二分查詢 \(l\)

判斷內容就是差分,查詢的時候看每一天是否滿足 \(room[i]\) 要求即可。

\(Code\)

Part 2 二維差分

和二維字首和大同小異。

回顧一下二維字首和:

sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]

P3397 地毯

先考慮修改,時間是 \(O(1)\) 的。對四個方向操作即可。

再考慮查詢:

透過看查詢的步驟,就知道操作的意義了。其實和一維差分的性質是一樣的。邊界開頭就增加,到了邊界就減去。

在遍歷的時候就是 \(O(n^2)\),即:

d[i][j]=d[i-1][j]+d[i][j-1]-d[i-1][j-1]+a[i][j]

於是就結束了。瞭解本質即可。

\(Code\)

Part 3 樹上差分

前置知識:LCA,可以左轉 LCA學習筆記

回顧差分的最基本本質:在頭(首位)加上修改的數,尾部減去修改的數,在遍歷中就可以實現對這個序列的操作。

樹上差分有兩種,一種是點差分,另外一種是邊差分。

先考慮邊差分。

我們設 \(d[i]\) 表示從 \(i\) 到他的父親的邊的修改的值的和

假設我們需要給 \(p\)\(q\) 之間的邊加上一個 \(x\)

由於樹有兩個性質:

  1. 任意兩個結點之間有且只有一條路徑。
  2. 一個結點只有一個父結點(即只有一條返祖邊)。

所以對兩點之間的邊的修改,就可以拆成\([p,lca(p,q)]\)\([q,lca(p,q)]\) 這兩條路徑。

於是乎就是數列上的差分了。就是
$ d[p]+=x,d[lca(p,q)] -=x,d[q]+=x,d[lca(p,q)] -=x $。

我們只需要如下操作即可:

\[d[p]+=x,d[q]+=x,d[lca(p,q)] -=2x \]

注意,在計算的時候,是由下往上回溯的,統計的是以 \(u\) 為根的子樹的和,如果當前的點 \(u\) 高度大於 \(p\) 且包含 \([lca(p,q),p]\) 內的結點,那麼他的子樹內必定包含 \([q,lca(p,q)]\) 的點,所以 \(d[lca(q,p)]\) 只會減一次且不會減多。

第二種就是點差分。我們就用 \(d[i]\) 表示當前 \(i\) 的點所增加的值。我們還是增加 \([p,q]\) 間點的路徑,我們首先是對 \(d[p]+=x,d[q]+=x\),但是這樣的話 \(lca(p,q)\) 就會多加一個 \(x\) ,我們需要減去。但是現在還有一個 \(x\) 沒有減去,按照一維差分,所以我們要在 \(lca(p,q)\) 的父親處減去一個 \(x\)

所以點差分的操作就是:

\[d[p]+=x,d[q]+=x,d[lca(q,p)]-=x,d[fa(lca(q,p)]-=x \]

P8805 機房

樹上字首和模板,拿來練手的,不多說了。

自己寫的題解

P3128 [USACO15DEC]Max Flow P

模板題,顯而易見的事情,每次對隔間,也就是點 \(p,q\) 進行操作,板子點差分,不講。

\(Code\)

P3258 松鼠的新家

每次對參觀的兩個點進行操作,但是要注意,兩次操作之間的起始點是不算的。在最後需要減去。注意終點也要減一。

剩下的還是點差分。

\(Code\)

相關文章