前缀和:前缀和顾名思义就是前面i个数的总和
a[0]=0;
for(int i=1;i<=n;i++)a[i]+=a[i-1];
给出一串长度为n的数列a1,a2,a3…an,再给出m个询问,每次询问给出L,R两个数,要求给出区间[L,R]里的数的和
数组a在经过这样的操作之后,对于每次的询问,我们只需要计算a[R]-a[L-1]。
二维前缀和:通过画图很容易就能知道:假如我想求a[3][4]的前缀和,我得先加上a[2][4]的前缀和,再加上a[3][3]的前缀和,然后这个时候我们发现实际上a[2][3]这个部分我们加了两遍,所以我们需要再减去一遍a[2][3],于是得出公式a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1]。
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1];
}
应用:给定一个n*m大小的矩阵a,有q次询问,每次询问给定x1,y1,x2,y2四个数,求以(x1,y1)为左上角坐标和(x2,y2)为右下角坐标的子矩阵的所有元素和。注意仍然包含左上角和右下角的元素。
int a[maxn][maxn];
int main()
{
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++)
a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1];
}
for(int i=1;i<=q;i++){
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
int ans=a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1];
cout<<ans<<endl;
}
}
差分:给你一串长度为n的数列a1,a2,a3…an,要求对a[L]~a[R]进行m次操作:
1:将a[L]~a[R]内的元素都加上P
2:将a[L]~a[R]内的元素都减去P
最后再给出一个询问求a[L]-a[R]内的元素之和
最简单的做法:于m次操作每次都遍历一遍a[L]~a[R],给区间里的数都加上P或减去P,最后再求一次前缀和
可是当n,m很大时就会超时,这时候就用到差分了。
int a[maxn],b[maxn];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
int L,R,t,p;
cin>>t>>L>>R>>p;
if(t==1){
b[L]+=p;b[R+1]-=p;
}
else{
b[L]-=p;b[R+1]+=p;
}
}
int add=0;
for(int i=1;i<=n;i++){
add+=b[i];
a[i]+=a[i-1]+add;
}
int x,y;
cin>>x>>y;
cout<<a[y]-a[x-1]<<endl;
}
为什么操作1时b[R+1]要减去p呢?因为操作一我只需对[L,R]区间里的数加p,[R+1,n]这个区间里的数没加p,所以需要减掉p。
差分在二维前缀和里的应用:
for(int i=0;i<m;i++){
int x1,y1,x2,y2,p;
cin>>x1>>y1>>x2>>y2>>p;
b[x1][y1]+=p;b[x2+1][y2+1]+=p;
b[x2+1][y1]-=p;b[x1][y2+1]-=p;
}
HDU 6514
只要把监控能看到的地方标记成1
给盗贼范围的时候看看盗贼范围内每个格子是否是1就能判断能否看到全部盗贼
解决方法是先用二维差分标记监控范围
然后求前缀和
然后把所有大于1的格子改成1
再进行一次前缀和
判断的时候只要求出盗贼格子的数量是否等于这些格子的和
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
m=m+7;
n=n+7;
int ant[n][m];
memset(ant,0,sizeof(ant));
int p;
scanf("%d",&p);
int x1,x2,y1,y2;
while(p--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
ant[x1][y1]++;
ant[x2+1][y2+1]++;
ant[x2+1][y1]--;
ant[x1][y2+1]--;
}
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
ant[i][j]+=ant[i-1][j]+ant[i][j-1]-ant[i-1][j-1];
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
if(ant[i][j])ant[i][j]=1;
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
ant[i][j]+=ant[i-1][j]+ant[i][j-1]-ant[i-1][j-1];
scanf("%d",&p);
while(p--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int sum=ant[x2][y2]+ant[x1-1][y1-1]-ant[x1-1][y2]-ant[x2][y1-1];
int q=(x2-x1+1)*(y2-y1+1);
if(sum>=q)printf("YES\n");
else printf("NO\n");
}
}
return 0;
}