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