『题解』AtCoder AT2145 [ABC047B] すぬけ君の塗り絵 2 イージー / Snuke's Coloring 2 (ABC Edit)
题目大意
有一个左上角为 \((0,0)\),右下角为 \((W,H)\) 的矩阵,初始时全部为白色。
给出 \(N\) 个操作,每个操作给定一个点 \((x_i,y_i)\) 和一个参数 \(a_i\),代表:
- \(a_i=1\):将 \(x<x_i\) 的区域全部涂黑。
- \(a_i=2\):将 \(x>x_i\) 的区域全部涂黑。
- \(a_i=3\):将 \(y<y_i\) 的区域全部涂黑。
- \(a_i=4\):将 \(y>y_i\) 的区域全部涂黑。
问操作后还剩下的白色区域的面积。
思路
可尝试暴力,直接按照题意模拟,最后统计面积,时间复杂度 \(\mathcal{O}(WHN)\),可过。
但还有更优雅的方法。我们发现,每次操作的区域都是一个矩形,而且是一行一行和一列一列地操作。考虑维护白色区域的左上角 \((x_1,y_1)\) 和右下角 \((x_2,y_2)\) 坐标,对于每次操作:
- \(a_i=1\):\(x_1 \gets \max\{x_1,x\}\),这个操作覆盖的是坐标点上面的所有行,故取 \(\max\)。
- \(a_i=2\):\(x_2 \gets \min\{x_2,x\}\),覆盖坐标点下面的所有行,故取 \(\min\)。
- \(a_i=3\):\(y_1 \gets \max\{y_1,y\}\),覆盖坐标点左边的所有列,故取 \(\max\)。
- \(a_i=4\):\(y_2 \gets \min\{y_2,y\}\),覆盖坐标点右边的所有列,故取 \(\min\)。
最后,若左上角坐标还在右下角坐标的后面,那么就没有白色区域,输出 \(0\)。
否则,输出坐标差之积,即为白色区域面积。
代码
#include <iostream>
using namespace std;
int w,h,n,x,y,a;
int x1,x2,y1,y2;
int main(){
cin >> w >> h >> n;
x2=w,y2=h; // x2 和 y2 不能忘了初始化
while(n--){
cin >> x >> y >> a;
switch(a){
case 1: x1=max(x1,x); break; // 1 操作涂的是第一行到当前行 -1,取最大值
case 2: x2=min(x2,x); break; // 2 操作涂的是当前行 +1 到最后一行,取最小值
case 3: y1=max(y1,y); break; // 3 操作涂的是第一列到当前列 -1,取最大值
case 4: y2=min(y2,y); break; // 4 操作涂的是当前列 +1 到最后一列,取最小值
default: break;
}
}
// 全部操作执行完成后,白色区域的矩阵左上角坐标为 (x1,y1),右下角坐标为 (x2,y2)
if(x1>x2 || y1>y2){
puts("0"); // 只要左上角在右下角的右下方,那么就没有白色区域
}else{
// 坐标差相乘即为白色区域面积
cout << (x2-x1)*(y2-y1) << endl;
}
return 0;
}

浙公网安备 33010602011771号