前缀和与差分
从一维差分到二维差分超详细题解,并严格遵守题解审核要求。
一、题意简述
- 给你
n 个第一象限的矩形。 - 第
i 个矩形的左下角的坐标为(x1_i,y1_i) ,右上角的坐标为(x2_i,y2_i) ,均是整数。 - 求正好被
k 个矩形覆盖的面积。 -
# 二、题目分析 ## 1.基本思路 首先我们把第一象限拆成 $1000\!\times \!1000$ 个格子,每个格子的坐标是它的左下角的坐标,再建立一个数组,保存每个方格被多少个矩形覆盖,比如样例是这样的: 
每个格子被覆盖的次数用格子颜色的深浅直观地表现了出来。
只要数一数有多少个格子刚好被
2.较慢的方法
怎么求出每个格子被多少矩形覆盖了呢?最基本的思路是对每个矩形,将它覆盖的格子全都加上1。这种方法最坏情况复杂度是
3.一维差分前缀和
如果变成一维数组区间加,应该就能想到办法:线段树 差分+前缀和。(会的同学可直接跳至“5.二维差分前缀和”)
比如下面这张图,黑色和红色组成的柱子表示原数组,其中红色部分就是它的差分数组:
用公式表示就是:(差分简称
显然,差分与前缀和互为逆运算。
4.一维区间加
比如我们知道了一个数组
我们可以先区间加,再差分,找到规律。比如第二行是第一行的差分数组,第三行是将第一行第3-5项都加上v,第四行是第三行的差分。
可以看到,第四行与第二行的区别只在第3个数和第6个数,于是能得到这样的算法:
c[left]+=v;
c[right+1]-=v;
所以需要进行大量的区间加时,可以先进行差分,
5.二维差分前缀和
二维前缀和也很好定义。
但是差分显得不很直观,所以需要用差分是前缀和的逆运算的特点推。
由第三个式子顺便得到前缀和的递推式:
6.二维区间加
二维区间加我们仍然按照上面的方法推,但是用字母太麻烦,所以下面用数字。一下四个矩阵意义仍与上同,第三个的红色部分为
可以看到,上面矩阵的-1和0是由1-和-5加5得到的,-3和-7是由2和-2减5得到的,所以可以得到如下算法:(
c[x1][y1]+=v;
c[x2][y2]+=v;
c[x1][y2]-=v;
c[x2][y2]-=v;
7.最终做法
建立一个差分数组,一个原数组,读入每个矩形,用上述方法对差分数组操作实现区间加1。最后将差分数组进行前缀和得到原数组,统计
三、代码
#include<iostream>
using namespace std;
int n,k,ans,c[1010][1010],a[1010][1010];
//n,k意义如题,ans是答案,c是差分数组,a是原数组
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
c[x1][y1]++;//二维差分区间加
c[x2][y2]++;//
c[x1][y2]--;//
c[x2][y1]--;//
}
for(int i=0;i<=1005;i++)
for(int j=0;j<=1005;j++)
{
a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+c[i][j];//前缀和的递推式
if(a[i][j]==k)ans++;//恰被覆盖k次,统计
}
cout<<ans<<endl;
return 0;
}