洛谷P4514 上帝造題的七分鐘

2022-05-20 14:43:18 字數 2451 閱讀 5078

這是乙個二維區域修改區域查詢問題,可以考慮使用二維樹狀陣列解決。

我們先回憶一下一維區間修改區間查詢樹狀陣列是怎麼做的,因為樹狀陣列本身只支援求字首和的形式,每次修改也只能單點修改,因此結合字首和和單點修改的性質,我們想到可以用樹狀陣列來維護差分陣列,這樣就能做到區間修改單點查詢,但這還是不是我們需要的區間修改區間查詢。上面的差分陣列給了我們區間修改的啟發,下面我們令 \(d\) 為差分陣列,我們發現區間查詢同樣可以差分,於是我們的目標實際上是求這樣乙個式子(\(1 \sim i\) 的字首和):

\[\sum\limits_ ^ n \sum\limits_ ^ i d_j

\]可以考慮計算每個 \(d_j\) 對答案的貢獻,即:

\[\sum\limits_ ^ n d_i \times (n - i + 1)

\]為了能接下來我們讓 \(d_i\) 和 \(i\) 放在一起,將每次詢問不同的 \(n\) 拿開方便維護:

\[(n + 1)\sum\limits_ ^ n d_i - \sum\limits_ ^ n d_i \times i

\]於是我們驚奇地發現我們只需要維護出 \(\sum\limits_ ^ n d_i\) 以及 \(\sum\limits_ ^ n d_i \times i\) 即可。於是我們可以寫出如下**:

void add(int p, int k)

int query(int p)

signed main()

return 0;

}

同樣類似於上面那個思路,我們可以定義一下二維陣列的差分,即我們需要讓 \((1, 1) \sim (n, m)\) 的字首和為 \(a_\),可以考慮二維字首和的式子 \(s_ = s_ + s_ - s_ + a_ = a_ + a_ - a_ + a_\),於是我們只需令差分陣列 \(d_ = a_ - a_ - a_ + a_\) 即可。不難發現我們每次對某個位置 \((i, j)\) 進行修改,影響的是 \((i, j) \sim (n, m)\) 這一段區間,於是我們我們要給二維的一片區域 \((a, b) \sim (c, d)\) 加上某個數 \(x\),只需要在 \((a, b)\) 出加上 \(x\),在 \((a, d + 1), (c + 1, b)\) 出減去 \(x\),再在 \((c + 1, d + 1)\) 處加上 \(x\) 即可。因為可以使用差分,因此我們每次需要查詢的就是 \((1, 1) \sim (n, m)\) 這個區域的和,即:

\[\sum\limits_ ^ n \sum\limits_ ^ m \sum\limits_ ^ i \sum\limits_ ^ j d_

\]同樣的我們考慮每個 \(d_\) 對答案的貢獻,顯然 \(d_\) 會被 \((i, j) \sim (n, m)\) 這個區域內的所有數算一次,於是原式即:

\[\sum\limits_ ^ n \sum\limits_ ^ m d_ \times (n - i + 1) \times (m - j + 1)

\]\[= \sum\limits_ ^ n \sum\limits_ ^ m d_ \times (nm + n + m + 1 - mi - i - nj - j + ij)

\]同樣讓每個位置維護的值只與每個位置有關,將查詢的部分提出來有:

\[(nm + n + m + 1) \sum\limits_ ^ n \sum\limits_ ^ m d_ - (m + 1)\sum\limits_ ^ n \sum\limits_ ^ m d_ \times i - (n + 1)\sum\limits_ ^ m d_ \times j + \sum\limits_ ^ m d_ \times ij

\]於是我們每個位置維護四個值:\(\sum\limits_ ^ n \sum\limits_ ^ m d_, \sum\limits_ ^ m d_ \times i, \sum\limits_ ^ m d_ \times j, \sum\limits_ ^ m d_ \times ij\) 即可。

#includeusing namespace std;

#define n 2050 + 5

#define lowbit(x) (x & (-x))

char opt[n];

int n, m, a, b, c, d, k, c[n][n][4];

int read()

while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();

return x * f;

}void add(int x, int y, int k)

int query(int x, int y)

int main()

else printf("%d\n", query(c, d) - query(c, b - 1) - query(a - 1, d) + query(a - 1, b - 1));

}return 0;

}

洛谷P4514 上帝造題的七分鐘

第一分鐘,x說,要有矩陣,於是便有了乙個裡面寫滿了 0 的 n times m 矩陣。第二分鐘,l說,要能修改,於是便有了將左上角為 a,b 右下角為 c,d 的乙個矩形區域內的全部數字加上乙個值的操作。第三分鐘,k說,要能查詢,於是便有了求給定矩形區域內的全部數字和的操作。第四分鐘,彩虹喵說,要基...

洛谷4514 上帝造題的七分鐘(二維樹狀陣列)

好久沒寫部落格了.這段時間狂補一下 題目大意 給定乙個 n n 的全0矩陣,每次有兩種操作 l a b c d delta 表示將左上角 a,b 右下角 c,d 的矩陣加 delta k a b c d 表示求左上角 a,b 右下角 c,d 的矩陣的和並輸出 其中運算元 le 10 5 n le 2...

上帝造題的七分鐘2

xlk覺得 上帝造題的七分鐘 不太過癮,於是有了第二部。第一分鐘,x說,要有數列,於是便給定了乙個正整數數列。第二分鐘,l說,要能修改,於是便有了對一段數中每個數都開平方 下取整 的操作。第三分鐘,k說,要能查詢,於是便有了求一段數的和的操作。第四分鐘,彩虹喵說,要是noip難度,於是便有了資料範圍...