chenfy27的刷题记录

导航

abc370D Cross Explosion

有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;
}

posted on 2024-10-07 18:03  chenfy27  阅读(16)  评论(0)    收藏  举报