[差分入门讲解] 洛谷P3397地毯

题目中文不再赘述

这道题一个很显然的思路是暴力枚举每块地毯能覆盖到的位置,然后再输出,发现复杂度O(????),很迷,显然过不去

有小伙伴说了,开线段树维护!对,没错,可以过,但是我要引入一个新的概念----->差分

什么是差分?

具体的概念我也说不清,不过我们可以通过这道题来引入,然后自己去感性理解

加入我们的地毯是一个这样的地图

[0][0][0][0][0][0][0][0][0]

假如我们要将2~6用地毯盖住,那么根据暴力的思路,他应该处理完后长这样

[0][1][1][1][1][1][1][0][0]

然后我们就发现一个很神奇的性质

假如我们只在第2个位置存一个1,那么我们可以通过求2~6的前缀和来达到相同的效果

[0][1][0][0][0][0][0][0][0]->[0][1][1][1][1][1][1][1][1]

然后发现6后面的数组也有了值,但这时他还没有被覆盖,怎么办呢?我们只需要在第七个位置填入-1就好

[0][1][0][0][0][0][0][-1][0]->[0][1][1][1][1][1][1][0][0]

小伙伴们又要问了,那这个-1不会影响后续的地毯吗?答案是不会的,因为我们通过前面求过来时,1+-1=0,对当前位置的贡献为零,假如当前位置有值,那么先减一再加一,不就相当于没有变化吗?

上面这种只在一段区间的左端点和右端点+1的位置来存放整个区间的变化的方法,就叫差分,差分的应用还可以有求前缀和,比如你有一段区间,你可以给子区间加ci,然后求和,我们可以先预处理一个每一项和前一项的差的数组,我们加ci时,发现ci只对这个子区间的左端点 和右端点+1有影响,因为左端点+ci,那么他和他前一项的差就增大了ci,右端点+ci,那么右端点+1和右端点的差就小了ci,上述操作只在预处理的数组上进行,并不改变原数组,然后处理需要树状数组,不细讲,有兴趣看这个树状数组的应用

然后是这道题的代码

#include<cstdio>
#include<iostream> 
using namespace std;
int n,m;
int x1,y1,x2,y2;
int map[1050][1050];
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		for (int k=x1;k<=x2;k++)//因为是二维,所以每一层都要这么处理
		map[k][y1]++,map[k][y2+1]--;
	}
	for (int i=1;i<=n;i++)
	{
		for (int k=1;k<=n;k++)
		map[i][k]+=map[i][k-1],cout<<map[i][k]<<" ";//直接前缀和
		puts("");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值