题目链接: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;
}