[学习笔记]二维前缀和+差分
题面
导入
先来了解一下差分。
有一个$1~n$的序列,请将它的前$m$($m < n$)项$+1$,并求出前$n$项的前缀和。
你可以新建一个数组并清零,在第一项加上一个$1$,并在第$m+1$项填上一个$-1$。
设$n = 6,m = 4$
|原序列|1|2|3|5|7|4|
|-|-|-|-|-|-|
|新数组|1|0|0|0|-1|0|
接着,求一遍新数组的前缀和:
|新数组|1|1|1|1|0|0|
|-|-|-|-|-|-|
然后把新数组的前缀和加到原序列中
|最终数组|2|3|4|6|7|4|
|-|-|-|-|-|-|
所以就求出来了
二维前缀和+差分
读题可知,输入$x1,y1,x2,y2$
需要将这个矩阵中的所有的数$+1$
二维其实和一维差不多,只是把一个一维序列倒过来:
|1|
|-|
|2|
|3|
|5|
|7|
|4|
所以只需要把矩阵左上角$+1$,右上角的后一个$-1$,右下角$+1$,左下角的下一个元素$-1$
接着统计前缀和的时候,$mapp[i][j] = mapp[i][j] + mapp[i][j - 1] + mapp[i - 1][j] - mapp[i - 1][j - 1]$
code
#include <bits/stdc++.h>
using namespace std;
int mapp[5010][5010];
void read(int &x){
x = 0;
bool flag = true;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-')
flag = false;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
if(!flag)
x = -x;
}
int main(){
int n,m,q;
read(n);
read(m);
read(q);
for(int i = 1;i <= q;i++){
int x1,y1,x2,y2;
read(x1);
read(y1);
read(x2);
read(y2);
mapp[x1][y1]++;
mapp[x2 + 1][y2 + 1]++;
mapp[x1][y2 + 1]--;
mapp[x2 + 1][y1]--;
}
for(int i = 1;i <= n + 1;i++){
for(int j = 1;j <= m + 1;j++){
mapp[i][j] += mapp[i][j - 1] + mapp[i - 1][j] - mapp[i - 1][j - 1];
}
}
long long ans = 0;
for(register long long i = 1;i <= n;i++){
for(register long long j = 1;j <= m;j++){
if(mapp[i][j] == 0)continue;
ans += 2;
if(mapp[i][j] > mapp[i][j - 1])
ans += (long long)mapp[i][j] - mapp[i][j - 1];
if(mapp[i][j] > mapp[i - 1][j])
ans += (long long)mapp[i][j] - mapp[i - 1][j];
if(mapp[i][j] > mapp[i + 1][j])
ans += (long long)mapp[i][j] - mapp[i + 1][j];
if(mapp[i][j] > mapp[i][j + 1])
ans += (long long)mapp[i][j] - mapp[i][j + 1];
}
}
printf("%lld\n",ans);
}