有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;
}
标签:Explosion,int,stH,abc370D,Cross,stW,erase,ans,it2
From: https://www.cnblogs.com/chenfy27/p/18450383