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

匿名 (未验证) 提交于 2019-12-03 00:34:01

题目中文不再赘述

这道题一个很显然的思路是暴力枚举每块地毯能覆盖到的位置,然后再输出,发现复杂度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; }

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!