「第一分鐘,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難度,於是便有了資料範圍...