『题解』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;
}
posted @ 2022-01-25 09:46  仙山有茗  阅读(63)  评论(0)    收藏  举报