洛谷 P3397 地毯 【二维差分标记】
题目背景
此题约为NOIP提高组Day2T1难度。
题目描述
在n*n的格子上有m个地毯。
给出这些地毯的信息,问每个点被多少个地毯覆盖。
输入输出格式
输入格式:
第一行,两个正整数n、m。意义如题所述。
接下来m行,每行两个坐标(x1,y1)和(x2,y2),代表一块地毯,左上角是(x1,y1),右下角是(x2,y2)。
输出格式:
输出n行,每行n个正整数。
第i行第j列的正整数表示(i,j)这个格子被多少个地毯覆盖。
输入输出样例
输入样例#1:
5 3
2 2 3 3
3 3 5 5
1 2 1 4
输出样例#1:
0 1 1 1 0
0 1 1 0 0
0 1 2 1 1
0 0 1 1 1
0 0 1 1 1
说明
样例解释
0 0 0 0 0 0 0 0 0 0 0 1 1 1 0
0 1 1 0 0 0 1 1 0 0 0 1 1 0 0
0 1 1 0 0 -> 0 1 2 1 1 -> 0 1 2 1 1
0 0 0 0 0 0 0 1 1 1 0 0 1 1 1
0 0 0 0 0 0 0 1 1 1 0 0 1 1 1
数据范围
对于20%的数据,有n<=50,m<=100。
对于100%的数据,有n<=1000,m<=1000。
【題意】:略
【分析】://by阮行止
n*n的矩阵,每次给一个子矩阵 区间+1 。最后输出整个矩阵。
优化。用二维线段树或二维树状数组完成上面的操作。
足以吊打此题。
但是NOIP是不会考二维数据结构的
考虑这个问题的一维版:一个序列,最开始全是 0 .每次区间加 1 ,最后输出每个数。
于是有一种叫做“差分”的奇技淫巧:
假设我们现在要给[2,5]这个区间加一。原来的序列是:
0 0 0 0 0 0 0 0
这时候我们在2上面打 +1 标记, 6 上面打 -1 标记。那么现在的序列是:
0 +1 0 0 0 -1 0
有什么用呢?从左往右扫描这个数组,记录当前经过的标签之和。这个和就是对应那个数的答案。
这样,对于每个区间加操作,只需要O(1) 的时间打上标记。
最后扫描输出即可。
现在把问题拓展到二维。假设我们要覆盖[(2,2),(5,5)] ,那么标记便可以这样打:
0 0 0 0 0 0
0 +1 0 0 0 -1
0 +1 0 0 0 -1
0 +1 0 0 0 -1
0 +1 0 0 0 -1
0 0 0 0 0 0
即在每一行都按照一维的方式来操作
int sum=0,i,j;
for(i=1;i<=n+1;i++)
for(j=1;j<=n+1;j++)
sum+=flag[i][j],real[i][j]=sum;
之后 real 数组里就存了最后的矩阵。输出即可。
这个算法的复杂度是每次打标记O(n) ,总复杂度是O(mn+n^2)
【代碼】:[一維]
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
//#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[1005][1005];
int x[1005][1005];
const int maxn=1e5+10;
void fun(int x1,int y1,int x2, int y2)
{
for(int i=x1; i<=x2; i++)
{
for(int j=y1; j<=y2; j++)
{
a[i][j]++;
}
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
int x1,y1,x2,y2;
memset(a,0,sizeof(a));
while(m--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for(int i=x1;i<=x2;i++)
{
a[i][y1]++;
a[i][y2+1]--;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
x[i][j] = x[i][j-1] + a[i][j];
printf("%d ",x[i][j]);
}
printf("\n");
}
}
}
/*
5 3
2 2 3 3
3 3 5 5
1 2 1 4
0 1 1 1 0
0 1 1 0 0
0 1 2 1 1
0 0 1 1 1
0 0 1 1 1
0 0 0 0 0 0 0 0 0 0 0 1 1 1 0
0 1 1 0 0 0 1 1 0 0 0 1 1 0 0
0 1 1 0 0 -> 0 1 2 1 1 -> 0 1 2 1 1
0 0 0 0 0 0 0 1 1 1 0 0 1 1 1
0 0 0 0 0 0 0 1 1 1 0 0 1 1 1
*/
首先这题的主要思想很多大佬都讲了:就是差分,但是我的写法和他们的写法又不一样。
本题数据范围为n<=1000,m<=1000。
当n<=1000,m<=1000000甚至m<=10000000怎么办呢?
这时不管是O(n)的修改,还是甚至是 O(log^2(n))O(log
2
(n)) ,都是跑不过的。
而我们有一个O(1)修改的做法:二维差分。
设b[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]。
这样每次修改b[i][j]相当于对任意 i\le x,j \le yi≤x,j≤y 对a[x][y]做同样的修改
然后每次修改就直接++b[x1][y1],--b[x2+1][y1],--b[x1][y2+1],++b[x2+1][y2+1]即可。
也就是用 O(1)O(1) 的复杂度表示 O(n^2)O(n
2
) 的覆盖(原话来自下面那篇题解“用O(1)复杂度来表示O(N)的覆盖”)
最后再直接a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+b[i][j]还原出原序列即可。
/* Author: CNYALI_LK
LANG: C++
PROG: 3397.cpp
*/
[二維]
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
//#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[1005][1005];
int x[1005][1005];
const int maxn=1e5+10;
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
int x1,y1,x2,y2;
memset(a,0,sizeof(a));
while(m--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
a[x1][y1]++; //
a[x2+1][y1]--;
a[x1][y2+1]--; //
a[x2+1][y2+1]++;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
a[i][j] += a[i-1][j] + a[i][j-1] - a[i-1][j-1];
printf("%d%c",a[i][j],j==n?'\n':' ');
}
}
}
}
我们借助这个图片研究一下。假设在这个矩阵(二维数组)中,我们要求和的是上图中红色区域。现在我们已经预处理出了所有点的前缀和,现在给定两个点(x1,y1),(x2,y2),我们要求 以这两个点连线为对角线的一个子矩阵的数值之和。暴力做法直接挨个加这个我就不再多说了,反正早晚都得TLE,我们重点考虑用前缀和的快速做法。
首先我们可以把s[x2][y2]求出来,它代表整个大矩形的前缀和,然后我们分别减去它左边多出来的一块的前缀和和下边多出来一块的前缀和,这样就是最终答案了?
不是!这不是最终答案。可以发现,在我们剪掉这两个多出的区域时,下边的一小块被减了两次,但减两次显然是不合理的,我们应该加回来。。
所以对于一次的查询答案ans应该等于s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]。
这个二维前缀和也称差分序列。
洛谷 P3397 地毯 【二维差分标记】的更多相关文章
- 洛谷 P3397 地毯
P3397 地毯 题目背景 此题约为NOIP提高组Day2T1难度. 题目描述 在n*n的格子上有m个地毯. 给出这些地毯的信息,问每个点被多少个地毯覆盖. 输入输出格式 输入格式: 第一行,两个正整 ...
- 洛谷1736(二维dp+预处理)
洛谷1387的进阶版,但很像. 1387要求是“全为1的正方形”,取dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1]))吧?这个有“只有对 ...
- 洛谷P1048 采药 二维dp化一维
题目描述 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个 ...
- 洛谷P3397 地毯(差分)
二维平面上的差分,我们可以对每行处理. 比如我们要把(2,2)(5,5)之间的矩形加上1,可以这样处理. 0 0 0 0 0 0 0 +1 0 0 0 -1 0 +1 0 0 0 -1 0 +1 0 ...
- Codeforces 1262E Arson In Berland Forest(二维前缀和+二维差分+二分)
题意是需要求最大的扩散时间,最后输出的是一开始的火源点,那么我们比较容易想到的是二分找最大值,但是我们在这满足这样的点的时候可以发现,在当前扩散时间k下,以这个点为中心的(2k+1)2的正方形块内必 ...
- Monitor HDU6514 二维差分入门学习
Monitor HDU 6514 二维差分入门学习 题意 小腾有\(n*m\)的田地,但是有小偷来偷东西,在一片矩形区域上,有一部分区域是监控可以覆盖到的,这部分区域由一个或多个包含于该矩形区域的小矩 ...
- Gym 102028J 扫描线/二维差分 + 解方程
题意:有一个二维平面,以及n个操作,每个操作会选择一个矩形,使得这个二维平面的一部分被覆盖.现在你可以取消其中的2个操作,问最少有多少块地方会被覆盖? 思路:官方题解简洁明了,就不细说了:https: ...
- 220514 T2 画画 (二维差分)
首先我们需要特判只涂了一种颜色的情况: (1)k=1,此时答案就是1:(2)k>1,涂的这种颜色肯定不能是第一个,答案是k-1; 对于其他正常情况,我们对于每个颜色找到一个最小的矩形(这个矩形内 ...
- HDU - 6514 Monitor(二维差分)
题意 给定一个\(n×m\)的矩阵.(\(n×m <= 1e7\)). \(p\)次操作,每次可以在这个矩阵中覆盖一个矩形. \(q\)次询问,每次问一个矩形区域中,是否所有的点都被覆盖. 解析 ...
随机推荐
- CF763B Timofey and Rectangles
题目戳这里. 首先答案肯定是YES,因为一个平面图肯定可以被4种颜色染色,关键是怎么输出方案. 由于4是一个特殊的数字\(4 = 2^2\),而我们还有一个条件就是边长为奇数,而奇数是会改变二进制位的 ...
- JQuery队列queue与原生模仿其实现
jQuery中的queue和dequeue是一组很有用的方法,他们对于一系列需要按次序运行的函数特别有用.特别animate动画,ajax,以及timeout等需要一定时间的函数. queue() 方 ...
- D. Relatively Prime Graph
Let's call an undirected graph G=(V,E)G=(V,E) relatively prime if and only if for each edge (v,u)∈E( ...
- zigbee ---- profile 和 cluster
在zigbee规范中,引入了profile, cluster的概念.具体说来,假设规范一个profile(可以理解成一套规定),这个profile用来规范智能家居领域的相关产品都要满足那些要求,那么h ...
- 数据仓库3级范式(3NF)基础
一.引言 最近在整理理大数据模式下的数据仓库数据模型,资料来自互联网和读过的数据仓库理论和实践相关. 二.3NF (1)1NF-无重复的列 数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个 ...
- Nginx替换过滤文本模块replace-filter-nginx-module
1.安装此模块需要先安装sregex运行库 apt-get update;apt-get install git make gcc -y #Centos改成yum git clone https:// ...
- jwplayer 部署方案1
<body> <div id="my_player" data_src="http://xx.com/jwplayer/uploads/test.mp4 ...
- input输入浮动提示
html代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...
- Nginx 默认配置解析
# For more information on configuration, see: # * Official English Documentation: http://nginx.org/e ...
- LOJ 6057 - [HNOI2016]序列 加强版再加强版
Description 给定一个长度为 \(n\le 3*10^6\) 的序列 \(q\le 10^7\) 次询问每次求区间 \([l,r]\) 的所有子区间的最小值的和 询问随机 Solution ...