分行做前綴和,再把直的前綴和加起來。
就是橫的做一次,直的做一次的意思。
這樣下來,二次前綴和陣列的[x][y]就會是原本陣列的[0][0]到[x][y]這整塊。
接下來,就可以用簡單的排容原理來得出任意區塊的總和了!(如果想不出來可以試著畫圖理解)
這樣的複雜度只有O(n*n+m)
比只做一次前綴和的O(n*n+m*n)
以及暴力加法的O(m*n*n)還快
(只做一次好像也會過就是了...)
然後是我的範例(把註解取消掉可以更了解原理)
#include<bits/stdc++.h>
using namespace std;
//template<class T>//ostream& operator<<(ostream& os,vector<T> v)//{// os<<" ";// for(int i=0; i<v.size(); i++)// {// os<<v[i]<<" ";// }// os<<"\n";// return os;//}
int main(){ ios::sync_with_stdio(false); cin.tie(0); int n,m,tmp; pair<int,int> a,b; vector<vector<int>> v; vector<vector<int>> p; while( cin>>n>>m) { v.clear(); p.clear(); vector<int> s(n); v.push_back(s); p.push_back(s); for(int i=1; i<=n; i++) { v.push_back({0}); p.push_back({0}); for(int j=1; j<=n; j++) { cin>>tmp; v[i].push_back(tmp); p[i].push_back(v[i][j]+p[i][j-1]); } } for(int i=0; i<=n; i++) { for(int j=1; j<=n; j++) { p[j][i]+=p[j-1][i]; } } //cout<<"\n"<<v; //cout<<"\n"<<p; for(int i=0; i<m; i++) { cin>>a.first>>a.second>>b.first>>b.second; cout<<p[b.first][b.second]-p[a.first-1][b.second]-p[b.first][a.second-1]+p[a.first-1][a.second-1]<<"\n"; } } return 0;}