---
# System prepended metadata

title: 二維前綴和

---

# 二維前綴和

表示(0,0)到(X,Y)矩形(綠色部分)內所有數值和
![](https://i.imgur.com/B5iAjZz.png)


### 建表
dp概念:
```cpp=
dp[x][y]=dp[x][y]+dp[x-1][y]+dp[x][y-1]-dp[x-1][y-1];
 綠  色    灰  色    紅  色      藍  色      黃  色   
```
<font color="#7B7B7B">**紅色**</font>+<font color="#f00">**紅色**</font>+<font color="#0000C6">**藍色**</font>-<font color="#FFD306">**黃色**</font>
![](https://i.imgur.com/2JLieHw.png)

### 查詢

設從(Sx,Sy)到(Ex,Ey)的矩形
![](https://i.imgur.com/OBeEqM4.png)

其範圍 =
```cpp=
dp[Ex][Ey]-dp[Sx-1][Ey]-dp[Ex][Sy-1]+dp[Sx-1][Sy-1]
  紅  色      綠  色        藍  色        粉  色
```
<font color="#f00">**紅色**</font>-<font color="#8CEA00">**紅色**</font>-<font color="#0000C6">**藍色**+</font><font color="#FF79BC">**粉色**</font>
![](https://i.imgur.com/McJ5pJl.png)


Code
```cpp=
int n,m;
cin >> n >> m;
for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
        cin >> pre[i][j];
        pre[i][j]=pre[i][j]+pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1];
    }
}
int q;
cin >> q;
while(q--){
    int x1,x2,y1,y2;
    cin >> x1 >> y1 >> x2 >> y2;
    x1--,y1--;
    int ans=pre[x2][y2]-pre[x2][y1]-pre[x1][y2]+pre[x1][y1];
    cout << ans << '\n';
}
    
```

## 二維矩形總和最大值

**一維DP的延伸**

1. 再輸入的時候就建立每一行的前綴和表

```cpp=
for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
        cin >> arr[i][j];
        arr[i][j]+=arr[i][j-1];
    }
}
```
2. 窮舉每行的區間和列數

```cpp=
for(int i=1;i<=n;i++){
    for(int j=i;j<=n;j++){  
        //窮舉行的左邊界及右邊界
        
        for(int k=1;k<=m;k++){  
            //窮舉列數
            ...
        }
    }
}
```
3. 利用一維連續元素最大合的dp概念延伸 : 因為i j已經決定好寬度了，就相當於一維的一個元素，接下來的k只要遍歷列就好了，當sum<0的時候就代表對未來的結果沒有幫助，就把sum設為0，如此一來就能找到矩形最大的和了。

```cpp=
for(int i=1;i<=n;i++){
    for(int j=i;j<=n;j++){
        int sum=0;
        for(int k=1;k<=m;k++){
            sum+=arr[k][j]-arr[k][i-1];
            if(sum>ans) ans=sum; 
            if(sum<0) sum=0;
        }
    }
}
```
