二维差分

  二维差分和一维差分思路上并没有什么区别,具体实现的区别就在于一维的直接对区间两端差分就好了,而二维的多了一维需要处理。

  差分的思想是和前缀和有关的,一维的前缀和我们都懂求,那么二维的呢?

  如图

  因为是从左到右,从上到下的遍历,当要求红色部分,(0,0)到(i,j)处的前缀和时,我们黄色部分和蓝色部分已经是已知的了,而它们重叠的部分就是绿色部分,所以把黄色和蓝色部分的结果加起来,再减去绿色部分,最后加上(i,j)处的值就是(i,j)位置的前缀和了。

  所以,二维前缀和就是sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]+sum[i-1][j-1]

  而我们要求左上角是(x1,y1),右下角是(x2,y2)的矩形区间内的值处理出前缀和后也可以O(1)时间内求出来。

  如图

  我们要求紫色部分的值,我们已知的是黄色部分的值,但它多了两个蓝色部分的值,而两个蓝色部分有重叠了个绿色部分

  所以要求的区间内的值就是sum[x2][y2]-sum[x2][y1-1]+sum[x1-1][y2]+sum[x1-1][x2-1]

二哥种花生

  中文题,二维前缀和的练手题。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 typedef long long ll;
 5 ll sum[1018][1018]={0};
 6 int main()
 7 {
 8     int n,m,l,w;
 9     while(~scanf("%d%d",&n,&m))
10     {
11         for(int i=1;i<=n;i++)
12             for(int j=1;j<=m;j++)
13                 scanf("%lld",&sum[i][j]);
14         for(int i=1;i<=n;i++)
15             for(int j=1;j<=m;j++)
16                 sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
17         scanf("%d%d",&l,&w);
18         ll ans=0;
19         //题目给的l,w不是说(0,0)到(l,w)的矩形
20         //而是长为l,宽为w的矩形
21         //枚举左上角
22         for(int x1=1;x1<=n;x1++)
23             for(int y1=1;y1<=m;y1++)
24             {
25                 int x2=x1+l-1,y2=y1+w-1;
26                 if(x2<=n&&y2<=m)//右下角在范围内
27                     ans=max(ans,sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]);
28             }
29         printf("%lld\n",ans);
30     }
31     return 0;
32 } 

一维都会了,二维也不难

  照这样画图的方法我们,也可以得出差分值的放置位置,一维时是在需要更新的位置开始,不需要的位置结束,而二维的也一样。

  如果我们要在左上角是(x1,y1),右下角是(x2,y2)的矩形区间每个值都+a

  如图

  在我们要的区间开始位置(x1,y1)处+a,根据前缀和的性质,那么它影响的就是整个黄色部分,多影响了两个蓝色部分,所以在两个蓝色部分-a消除+a的影响,而两个蓝色部分重叠的绿色部分多受了个-a的影响,所以绿色部分+a消除影响。

  所以就是dif[x1][y1]+=a,dif[x1][y2+1]-=a,dif[x2+1][y1]-=a,dif[x2+1][y2+1]+=a

HDUOJ6514Monitor

  这道让我开始学差分的题。。。

  题目大意:先给出一个n*m的范围,然后给出p个监控矩形的左下角和右上角,最后有q个询问,问给出左下角和右上角的矩形是否完全被监控到。

  没学差分之前一直想用线段树来维护来做,但很麻烦根本不会做,而学了差分之后,因为p个矩形是已经选给出了,所以我们可以离线处理这些矩形,类似于一维的那道牛客的区间覆盖的问题,我们dif的差分数组可以得出(i,j)这个位置被多少个监控监控到,然后我们让被监控到的点权值为1,然后维护一个被监控到的点数的前缀和,那么询问的矩形要是被监控到的点等于面积,那么就是yes,否则就是no,恶心的地方就在于这题不能开二维数组,需要降维处理。

 1 #include<cstdio>
 2 const int N=13142118;
 3 int dif[N],cov[N];
 4 //cov被监控到的点的前缀和
 5 int main()
 6 {
 7     int n,m,p,q,x1,y1,x2,y2;
 8     while(~scanf("%d%d",&n,&m))
 9     {
10         for(int i=0;i<n;i++)
11             for(int j=0;j<m;j++)
12             {
13                 dif[i*m+j]=0;
14                 cov[i*m+j]=0;
15             }
16         scanf("%d",&p);
17         while(p--)
18         {
19             scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
20             x1--,y1--,x2--,y2--;
21             dif[x1*m+y1]++;
22             if(x2+1<n)
23                 dif[(x2+1)*m+y1]--;
24             if(y2+1<m)
25                 dif[x1*m+y2+1]--;
26             if(x2+1<n&&y2+1<m)
27                 dif[(x2+1)*m+(y2+1)]++;
28         }
29         for(int i=0;i<n;i++)
30         {
31             for(int j=0;j<m;j++)
32             {
33                 if(i)
34                     dif[i*m+j]+=dif[(i-1)*m+j];
35                 if(j)
36                     dif[i*m+j]+=dif[i*m+j-1];
37                 if(i&&j)
38                     dif[i*m+j]-=dif[(i-1)*m+j-1];
39                 //如果这个位置有被监控到就是设为1
40                 if(dif[i*m+j]>=1)
41                     cov[i*m+j]=1;
42                 else
43                     cov[i*m+j]=0;
44                 if(i)
45                     cov[i*m+j]+=cov[(i-1)*m+j];
46                 if(j)
47                     cov[i*m+j]+=cov[i*m+j-1];
48                 if(i&&j)
49                     cov[i*m+j]-=cov[(i-1)*m+j-1];
50             }
51         }
52 //        for(int i=n-1;i>=0;i--)
53 //        {
54 //            for(int j=0;j<m;j++)
55 //                if(dif[i*m+j]>=1)
56 //                    printf("1 ");
57 //                else
58 //                    printf("0 ");
59 //            printf("\n");
60 //        }
61         scanf("%d",&q);
62         while(q--)
63         {
64             scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
65             int area=(x2-x1+1)*(y2-y1+1),cova=0;
66             x1--,y1--,x2--,y2--;
67             cova+=cov[x2*m+y2];
68             if(x1-1>=0)
69                 cova-=cov[(x1-1)*m+y2];
70             if(y1-1>=0)
71                 cova-=cov[x2*m+y1-1];
72             if((x1-1)>=0&&(y1-1)>=0)
73                 cova+=cov[(x1-1)*m+(y1-1)];
74         //    printf("%d %d\n",area,cova);
75             if(area==cova)
76                 printf("YES\n");
77             else
78                 printf("NO\n");
79         }
80     }
81     return 0;
82 } 

差分太猛了

NOIAC#71画画鬼才

原文地址:https://www.cnblogs.com/LMCC1108/p/10753451.html

时间: 2024-08-30 14:39:12

二维差分的相关文章

Gym 102028J 扫描线/二维差分 + 解方程

题意:有一个二维平面,以及n个操作,每个操作会选择一个矩形,使得这个二维平面的一部分被覆盖.现在你可以取消其中的2个操作,问最少有多少块地方会被覆盖? 思路:官方题解简洁明了,就不细说了:https://codeforces.com/blog/entry/63729. 此处重点记录一下两种做法的巧妙之处. 1:二维差分+解方程 二维差分:假设在矩形[(x1, y1), (x2, y2)]上加一个数,那么在(x1, y1), (x2 + 1, y2 + 1)加1, (x1, y2 + 1), (x

Codeforces Round #578 (Div. 2) 二维差分 可做模板

题意: 在n*n的矩阵中,你可以选择一个k*k的子矩阵,然后将这个子矩阵中的所有B全部变为W,问你怎么选择这个子矩阵使得最终的矩阵中某一行全是W或者某一列全是W的个数最多 题解:考虑每一行和每一列,对于特定的一行来说,要想让其全变为W,那么子矩阵的左上角端点是在一个范围中的,因此我们可以把范围中的每一个值加1 为了速度选择用二维差分来做,最终矩阵中的最大值就是答案 此题可以作为二维差分模板 #include<bits/stdc++.h> #define forn(i, n) for (int

二维差分前缀和——cf1202D(好题)

直接枚举每个点作为左上角是可以做的,但是写起来较麻烦 有一种较为简单的做法是对一列或一行统计贡献 比如某一行的B存在的区间是L,R那么就有三种情况 1.没有这样的区间,即一行都是W,此时这行对答案的贡献一直是1 2.R-L+1<=k,那么这一段必须要找一个点代表的矩形来覆盖,可以求出这样的点的存在区间是一个矩形,当且仅当点在这个矩形范围内时,这一行会有1的贡献. 3.R-L+1>k,永远不会有贡献 对于情况2,我们用二维的差分来统计一下,最后枚举每个点,看我们选择这个点代表的矩形时,贡献是否达

一维差分和二维差分

差分 一维: 原数组:\(c[i]\) 差分数组\(a[i]\):表示\(i{\sim}n\)的数,每一个数\(c[j](i<=j<=n)\)都加上一个\(a[i]\) 应用场景: ①把从第\(k-n\)位的数都加上一个\(w\) a[k]+=w; ②把从第\(i\)位到第\(j\)位的数都加上一个\(w\) a[i]+=w,a[j+1]-=w; 前提是需要对数组,进行多次①②这样的操作,使用差分才有意义,不然直接暴力就可以了 要注意的是①②操作只是把那些加减操作缓存了起来,而并不是完全分布给

cf1200 D White Lines(二维差分)

题目大意 有一个大小为n的矩阵,每个1*1的单位为黑或白,我们可以用一个(只有一个)大小为k*k的白色矩阵覆盖,问:最多的时候有几条白线(横的全为白 或竖的全为白 即为白线). 思路 要想把一条线(以横的为例)全变为白的,那么我们就需要从这一行最左边的黑色块覆盖到最右边的黑色块,如果两端距离超过k,则无法覆盖,否则就一定可以.那么就一定会产生一个矩阵,选取这个矩阵里面的任何一个点 都可以将这行变为白线:反之,矩阵外的一定不行.所以,可以用差分数组,因为只要选了矩阵里的点,答案就一定就加一.然后二

Problem 3 二维差分

$des$ 考虑一个 n ∗ n 的矩阵 A,初始所有元素均为 0.执行 q 次如下形式的操作: 给定 4 个整数 r,c,l,s, 对于每个满足 x ∈ [r,r+l), y ∈ [c,x−r+c]的元素 (x,y),将权值增加 s.也就是,给一个左上顶点为 (r,c).直角边长为 l 的下三角区域加上 s.输出最终矩阵的元素异或和. $sol$ 每次加减是一个等腰直角三角形 考虑对每行查分 即对垂直于 x 轴的腰上的每个点 +1 ,所有斜边的后一个点 -1 这样的话,每行形成了查分数组 简化

bzoj3132 上帝造题的七分钟(差分+二维树状数组)

bzoj3132 上帝造题的七分钟(差分+二维树状数组) Time Limit: 20 Sec Memory Limit: 128 MB Description "第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作. 第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作. 第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围. 第五分

POJ2155/LNSYOJ113 Matrix【二维树状数组+差分】【做题报告】

这道题是一个二维树状数组,思路十分神奇,其实还是挺水的 题目描述 给定一个N∗NN∗N的矩阵AA,其中矩阵中的元素只有0或者1,其中A[i,j]A[i,j]表示矩阵的第i行和第j列(1≤i,j≤N)(1≤i,j≤N),初始矩阵元素都是0.在矩阵上进行TT次操作,操作有以下两种: (1)格式为C x1 y1 x2 y2(1≤x1≤x2≤n,1≤y1≤y2≤n)C x1 y1 x2 y2(1≤x1≤x2≤n,1≤y1≤y2≤n) ,其中CC为字符“C”,表示把以(x1,y1)(x1,y1)为左上角,

HDU-6514 Monitor(二维前缀和+差分)

http://acm.hdu.edu.cn/showproblem.php?pid=6514 Problem Description Xiaoteng has a large area of land for growing crops, and the land can be seen as a rectangle of n×m. But recently Xiaoteng found that his crops were often stolen by a group of people,