有H行W列的格子,初始时每个格子中都是墙,接下来有Q组询问,格式为:R[i] C[i],表示在坐标(R[i],C[i])的地方放置炸弹,如果该位置是墙,则墙被炸掉,如果是空地,则上下左右最近的一格墙被炸掉。问最终还剩多少墙?
1<=H,W; H*W<=4E5; 1<=Q<=2E5; 1<=R[i]<=H; 1<=C[i]<=W
分析:用set维护按行和列的墙集合,模拟即可。注意在处理完左后,处理右时要重新find,因为删除会导致迭代器失效,处理上下也是类似的。
#include <bits/stdc++.h>
using i64 = long long;void solve() {int H, W, Q;std::cin >> H >> W >> Q;std::vector<std::set<int>> stH(H+1), stW(W+1);for (int i = 1; i <= H; i++) {for (int j = 1; j <= W; j++) {stH[i].insert(j);stW[j].insert(i);}}int ans = H * W;for (int i = 0; i < Q; i++) {int r, c;std::cin >> r >> c;if (stH[r].count(c)) {stH[r].erase(c);stW[c].erase(r);ans -= 1;} else {auto it1 = stH[r].lower_bound(c);if (it1 != stH[r].end()) {int z = *it1;stH[r].erase(z);stW[z].erase(r);ans -= 1;}auto it2 = stH[r].lower_bound(c);if (it2 != stH[r].begin()) {--it2;int z = *it2;stH[r].erase(z);stW[z].erase(r);ans -= 1;}auto it3 = stW[c].lower_bound(r);if (it3 != stW[c].end()) {int z = *it3;stW[c].erase(z);stH[z].erase(c);ans -= 1;}auto it4 = stW[c].lower_bound(r);if (it4 != stW[c].begin()) {--it4;int z = *it4;stW[c].erase(z);stH[z].erase(c);ans -= 1;}}}std::cout << ans << "\n";
}int main() {std::cin.tie(0)->sync_with_stdio(0);int t = 1;while (t--) solve();return 0;
}