前缀和与差分:一维与二维区间操作

发布于 2025-04-14 19:41 579 字 3 min read

hainoir avatar

hainoir

记录前端实践、算法推演和那些值得反复理解的问题。

  1. 至今

    超星

    前端研发工程师

  2. 至

    好未来

    硬件运维工程师

首页 周刊 时间线 关于 歌单
对照一维与二维场景,整理前缀和的区间求和公式、差分的区间更新方法,以及从差分还原数组的步骤,附 C++ 题目实现供复习和查阅。

一维前缀和

p[i] = p[i-1] + a[i];

优点:便于数组查找

//https://www.starrycoding.com/problem/7
#include <bits/stdc++.h>
using namespace std;
using ll =long long;
const int N = 1e5+9;
ll a[N],p[N];

int main(){
   ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
   int T;cin >> T;
   while(T--){
   	ll n,q;cin >> n >> q;
   	for(int i = 1;i <= n;i++){
   		cin >> a[i];
   	}
   	for(int i = 1;i <= n;i++){
   		p[i] = p[i-1] + a[i];
   	}
   	while(q--){
   		ll l,r;cin >> l >> r;
   		cout << p[r] - p[l-1] << '\n';		
   	}
   }
}

一维差分

d[i] = a[i] - a[i-1];

优点:便于数组修改

//https://www.starrycoding.com/problem/8
#include <bits/stdc++.h>
using namespace std;
using ll =long long ;
const int N = 1e5+9;
ll a[N],c[N],d[N];

int main(){
   ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
   ll n,p,q;cin >> n >> p >> q;
   for(int i = 1;i <= n;i++)cin >> a[i];
   for(int i = 1;i <= n;i++)d[i] = a[i] - a[i-1];
   while(p--){
   	ll l,r,x;cin >> l >> r >> x;
   	d[l] += x;d[r+1] -= x;
   }
   for(int i = 1;i <= n;i++)a[i] = a[i - 1] + d[i];
   for(int i = 1;i <= n;i++)c[i] = c[i - 1] + a[i];
   while(q--){
   	ll l,r;cin >> l >> r;
   	cout << c[r] - c[l-1] << '\n';
   }
}

二维前缀和

p[i][j] = p[i-1][j] + p[i][j-1] - p[i-1][j-1] + a[i][j];

//https://www.starrycoding.com/problem/15
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3+9;
using ll = long long;
ll  a[N][N],p[N][N];

int main(){
   ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
   int n,m,q;cin >> n >> m >> q;
   
   for(int i = 1;i <= n;++i)
   	for(int j = 1;j <= m;++j)
   		cin >> a[i][j];

   
   for(int i = 1;i <= n;++i)
   	for(int j = 1;j <= m;++j)
   		p[i][j] = p[i-1][j] + p[i][j-1] - p[i-1][j-1] + a[i][j];
   	
   while(q--){
   	int res = 0;
   	int x1,y1,x2,y2;cin >> x1 >> y1 >> x2 >> y2;
   	res = p[x2][y2] - p[x1-1][y2] - p[x2][y1-1] + p[x1-1][y1-1];
   	cout << res << '\n';
   }
}

二维差分

差分求法

d[i][j] = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1]

以上这个求法,是将原式作为所求差分的前缀和。

标准求法

d[i][j] += a[i][j];

d[i + 1][j] -= a[i][j];

d[i][j + 1] -= a[i][j];

d[i + 1][j + 1] += a[i][j];

两种求法一样,可以互相推导

eg:d[i + 1][j] -= a[i][j]; = d[i][j] -= a[i-1][j]`

//https://www.starrycoding.com/problem/50

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int N = 1e3+10;
ll a[N][N], d[N][N];

int main(){
   ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
   int n,m,q;
   cin >> n >> m >> q;
   
   for (int i = 1; i <= n; i++)
   {
   	for (int j = 1; j <= m; j++)
   	{
   		cin >> a[i][j];
   		d[i][j] += a[i][j];
   		d[i + 1][j] -= a[i][j];
   		d[i][j + 1] -= a[i][j];
   		d[i + 1][j + 1] += a[i][j];
   	}
   }
   while (q--)
   {
   	int x1, x2, y1, y2, c;
   	cin >> x1 >> y1 >> x2 >> y2 >> c;
   	d[x1][y1] += c;
   	d[x1][y2 + 1] -= c;
   	d[x2 + 1][y1] -= c;
   	d[x2 + 1][y2 + 1] += c;
   }
   for (int i = 1; i <= n; i++)
   {
   	for (int j = 1; j <= m; j++)
   	{
   		a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + d[i][j];
   		cout << a[i][j] << ' ';
   	}
   	cout << '\n';
   }
   return 0;
}

本文作者:hainoir · CC BY-NC-SA 4.0

喜欢的话,留下你的评论吧~

评论加载中…

相关文章