GDUT ACM2022寒假集训 专题一 F(一维&二维差分)

更好的阅读体验请前往:Paxton的小破站

一、一维差分

1、原理

假设有一个数列,我们需要对数列中的一个区间加上或减去一个值,直接想到的便是遍历该区间逐项加减。

但是当请求的操作变得非常多的时候,每次请求都进行一次遍历会很容易爆时间,因此我们引入了差分这个算法。

差分的特点就是在进行多次操作少量查询的时候可以快速得出结果。

如下图所示,a[n]是输入的数列b[n]是差分数列,且b[n] = a[n] - a[n-1]
图中先求出原本的差分数列,然后将3,5,7这部分进行+1操作后,我们发现操作后原本的3对应的差分数列+1,4对应的差分数列-1

745tfJ.jpg

为什么会出现这样的情况呢,我们接着来看下图
初始时原数列和差分数列都是0,但是当我对差分数列的某一项+1/-1之后,由公式得出原数列自该项起后面的项全部都进行了+1/-1操作

745YY4.jpg

因此如果我们想将数列**[x,y]**部分进行+num,只需要在 x的差分数列上+numy+1的差分数列上-num 然后再对整个差分数列每一项求前缀和即得到结果

也就是b[x] + num , b[y+1] - num

和前缀和一样,差分也可以将两个数组合并为一个数组,如下图所示
74TR1J.jpg

二、二维差分

1、原理

二维差分即对一个矩形区间进行数据操作时使用

由下图所示,如果已知原数组a,则可以求得差分数组p[x][y] = a[x][y] - a[x-1][y] - a[x][y-1] + a[x-1][y-1]

数列由(0,0)开始时要注意边界问题

74vBng.jpg

得出差分数组之后,我们想要对原数组中的亮蓝色区域进行数据操作,则需要在(x1,y1)对差分数组+1,但是这样子操作将会影响整个蓝色区域,因此我们需要在紫色橙色区域的对应位置进行-1操作来抵消影响,由于这俩块区域有一个交错范围因此需要在红色区域的对应位置进行+1操作

74XuU1.jpg

推导得在(x1,y1)(x2,y2)范围进行数据操作的公式为

b[x1][y1]+val;
b[x2+1][y1]-val;
b[x1][y2+1]-val;
b[x2+1][y2+1]+val;

2、例题

原题链接:https://vjudge.net/contest/477276#problem/F

(1)题干

在 n×n 的格子上有 m 个地毯。

给出这些地毯的信息,问每个点被多少个地毯覆盖。

(2)输入格式

第一行,两个正整数 n (1 ≤ n ≤ 1000)、m (1 ≤ m ≤ 105),意义如题所述。

接下来 m 行,每行两个坐标(x1,y1)和(x2,y2),代表一块地毯,左上角是
(x1,y1),右下角是(x2,y2)。

(3)输出格式

输出 n 行,每行 n 个正整数。

第i行第j列的正整数表示(i,j)这个格子被多少个地毯覆盖。

(4)样例

Sample Input

4 3
1 1 3 3
2 2 4 4
3 1 4 3

Sample Output

1 1 1 0
1 2 2 1
2 3 3 1
1 2 2 1

3、题解

(1)分析

由于这道题的原数组都为0,我们就不用再计算差分数组了,直接进行数据操作即可

(2)代码

#include <iostream>
using namespace std;
int sum[1002][1002];
int n,m,x1,x2,y1,y2;

int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>x1>>y1>>x2>>y2;//读入操作区间
		sum[x1][y1]++;
		sum[x2+1][y1]--;
		sum[x1][y2+1]--;
		sum[x2+1][y2+1]++;
	}

	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)//直接计算前缀和
		{
            sum[i][j] = sum[i][j] + sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1];
			cout<<sum[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值