AtCoder461E题

题目链接:https://atcoder.jp/contests/abc461/tasks/abc461_e

题目大意:有一个N*N的网格,初始均为白色,现有Q条查询,其中每一条只能是以下查询之一:

  • 键入 1 :给出一个整数 R 。将网格顶部起第 R 行的所有单元格涂成黑色。
  • 输入 2 :给出一个整数 C 。将网格左起第 C 列的所有单元格涂成白色。

当Q次查询过后,要求我们输出该点网格中黑色单元格的数量。

思路:我们可以用时间戳表示操作顺序,用树状数组维护时间分布,增量计算颜色变化。

代码如下:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN =3e5+5;
int n, q;
int tr[MAXN], tc[MAXN];     // tr[i]: 行i最后涂黑时间, tc[j]: 列j最后涂白时间
int bitr[MAXN], bitc[MAXN]; // 树状数组: 维护时间分布

// 树状数组单点更新
void add(int bit[], int idx, int val) {
    idx++;
    for (; idx <= q + 5; idx += idx & -idx) bit[idx] += val;
}

// 树状数组前缀查询 [0, idx]
int sum(int bit[], int idx) {
    idx++;
    int res = 0;
    for (; idx > 0; idx -= idx & -idx) res += bit[idx];
    return res;
}

int main() {
    cin>>n>>q;

    // 初始: 所有行和列时间都为0
    add(bitr, 0, n);
    add(bitc, 0, n);

    long long ans = 0;

    for (int time = 1; time <= q; time++) {
        int op, x;
        scanf("%d %d", &op, &x);

        if (op == 1) {
            // 涂黑第x行: 统计tc < tr[x]的列数(已经是白色)
            int white = sum(bitc, tr[x] - 1);
            ans += n - white;  // 其余列从白变黑

            // 更新tr[x]
            add(bitr, tr[x], -1);
            tr[x] = time;
            add(bitr, tr[x], 1);

        } else {
            // 涂白第x列: 统计tr <= tc[x]的行数(已经是白色)
            int white = sum(bitr, tc[x]);
            ans -= n - white;  // 其余行从黑变白

            // 更新tc[x]
            add(bitc, tc[x], -1);
            tc[x] = time;
            add(bitc, tc[x], 1);
        }

        cout<<ans<<endl;
    }

    return 0;
}