洛谷P4514 上帝造題的七分鐘

2022-08-13 22:36:14 字數 3363 閱讀 2464

「第一分鐘,x說,要有矩陣,於是便有了乙個裡面寫滿了 \(0\) 的 \(n \times m\) 矩陣。

第二分鐘,l說,要能修改,於是便有了將左上角為 \((a,b)\),右下角為 \((c,d)\) 的乙個矩形區域內的全部數字加上乙個值的操作。

第三分鐘,k說,要能查詢,於是便有了求給定矩形區域內的全部數字和的操作。

第四分鐘,彩虹喵說,要基於二叉樹的資料結構,於是便有了資料範圍。

第五分鐘,和雪說,要有耐心,於是便有了時間限制。

第六分鐘,吃鋼琴男說,要省點事,於是便有了保證運算過程中及最終結果均不超過32位有符號整數型別的表示範圍的限制。

第七分鐘,這道題終於造完了,然而,造題的神牛們再也不想寫這道題的程式了。」

——《上帝造裸題的七分鐘》

所以這個神聖的任務就交給你了。

輸入資料的第一行為 \(x\)

\(n\)

\(m\),代表矩陣大小為 \(n \times m\)。

從輸入資料的第二行開始到檔案尾的每一行會出現以下兩種操作:

\(l\)

\(a\)

\(b\)

\(c\)

\(d\)

\(delta\) —— 代表將 \((a,b)\),\((c,d)\) 為頂點的矩形區域內的所有數字加上 \(delta\)。

\(k\)

\(a\)

\(b\)

\(c\)

\(d\) —— 代表求 \((a,b),(c,d)\) 為頂點的矩形區域內所有數字的和。

請注意,\(k\) 為小寫。

針對每個 \(k\) 操作,在單獨的一行輸出答案。

x 4 4

l 1 1 3 3 2

l 2 2 4 4 1

k 2 2 3 3

對於 \(10\%\) 的資料,\(1 \leq n \leq 16, 1 \leq m \leq 16\) , 操作不超過200個.

對於 \(60\%\) 的資料,\(1 \leq n \leq 512, 1 \leq m \leq 512\).

對於 \(100\%\) 的資料,\(1 \leq n \leq 2048, 1 \leq m \leq 2048, -500 \leq delta \leq 500\) ,操作不超過200000個,保證運算過程中及最終結果均不超過32位帶符號整數型別的表示範圍。

挺「模板」的題,但感覺思想很巧妙。

二維樹狀陣列。

先考慮一維的情況,則題中操作類似區間修改,區間查詢

眾所周知樹狀陣列的一大經典功能是區間修改,單點查詢

我們設出乙個差分陣列 \(d\),設原陣列為 \(a\),則 \(d[i]=a[i]-a[i-1]\)

有 \(a[n]=\sum\limits_^n d[i]\)

那麼區間修改 「 \([l,r]\) 加上 \(c\) 」 ,對於差分陣列,其實只需 \(d[l]+=c\) ,和 \(d[r+1]-=c\),也就是單點修改

「單點查詢」 查的是 \(a[i]\) ,也就是 \(d\) 的字首和,用樹狀陣列維護 \(d[i]\) 的某些區間的和即可。

區間查詢 \(\sum\limits_^r a[i]\) ,需要的就不只是 \(d[i]\) 的字首和了。

先把查詢分成 $\sum\limits_^r a[i] -\sum\limits_^ a[i] $

然後把式子拆開:

\[\begin

\begin

\sum\limits_^n a[i] &= \sum\limits_^n \sum\limits_^i d[j] \\

&= \sum\limits_^n d[i] \times (n-i+1) \\

&= (n+1)\sum\limits_^n d[i] - \sum\limits_^n d[i] \times i

\end

\end

\]於是我們需要用兩個樹狀陣列分別維護 \(d[i]\) 及 \(d[i] \times i\) 的某些區間的和。

同樣還是差分,差分陣列 \(d[i][j]\) 滿足 \(a[n][m] =\sum\limits_^n \sum\limits_^m d[i][j]\)

那麼對於乙個左下角 \((a,b)\) 右上角 \((c,d)\) 的矩形加上 \(z\) ,其實就是 \(d[a][b]+=z\),\(d[c+1][d+1]+=z\) ,\(d[a][d+1]-=z\),\(d[c+1][b]-=z\)

可以理解成 \(d[i][j]\) 的值對所有它右上角的矩形的 \(a\) 有影響。

把每個矩陣查詢拆開,\(\sum\limits_^c \sum\limits_^d a[i][j]=\sum\limits_^c \sum\limits_^d a[i][j]-\sum\limits_^c \sum\limits_^ a[i][j]-\sum\limits_^ \sum\limits_^d a[i][j] + \sum\limits_^ \sum\limits_^ a[i][j]\)

然後再拆——

\[\begin

\begin

\sum\limits_^n \sum\limits_^m a[i][j] &= \sum\limits_^n \sum\limits_^m \sum\limits_^i \sum\limits_^j d[k][l] \\

&= \sum\limits_^n \sum\limits_^m d[i][j] \times (n-i+1) \times (m-j+1) \\

&= (n+1)(m+1)\sum\limits_^n \sum\limits_^m d[i][j] -(m+1) \sum\limits_^n \sum\limits_^m d[i][j] \times i -(n+1) \sum\limits_^n \sum\limits_^m d[i][j] \times j + \sum\limits_^n \sum\limits_^m d[i][j] \times i \times j

\end

\end

\]維護4個樹狀陣列即可。

**很是簡短。

#include#include#includeusing namespace std;

int read()

const int n = 2050;

int n,m;

int c[n][n],ci[n][n],cj[n][n],cij[n][n];

void add(int x,int y,int d)

}int sum(int x,int y)

int main()

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

return 0;

}

洛谷P4514 上帝造題的七分鐘

這是乙個二維區域修改區域查詢問題,可以考慮使用二維樹狀陣列解決。我們先回憶一下一維區間修改區間查詢樹狀陣列是怎麼做的,因為樹狀陣列本身只支援求字首和的形式,每次修改也只能單點修改,因此結合字首和和單點修改的性質,我們想到可以用樹狀陣列來維護差分陣列,這樣就能做到區間修改單點查詢,但這還是不是我們需要...

洛谷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難度,於是便有了資料範圍...