AT_abc432_d [ABC432D] Suddenly, A Tempest 题解

题目传送门

思路

考虑动态维护每一次风暴后每一个块的分布情况。先不考虑连通性。那每一次风暴后每一个块有两种情况:全部向一个方向平移,或分成两块分别向反方向移动。每一次直接暴力判断是哪种情况。最后跑 DFS 求出每一个连通块大小即可。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = (1 << 15);

struct node
{
	int x, y, x2, y2;
};

int n, stx, sty, res;
bool vis[N];
vector<node> pos, tmp;
map<int, vector<int> > mp[4];

void dfs(int u)
{
	if (vis[u]) return;
	int x = pos[u].x, y = pos[u].y, x2 = pos[u].x2, y2 = pos[u].y2;
	vis[u] = 1, res += (x2 - x + 1) * (y2 - y + 1);
	for (int v : mp[0][x2 + 1])
		if (y2 >= pos[v].y && pos[v].y2 >= y) dfs(v);
	for (int v : mp[1][y2 + 1])
		if (x2 >= pos[v].x && pos[v].x2 >= x) dfs(v);
	for (int v : mp[2][x - 1])
		if (y2 >= pos[v].y && pos[v].y2 >= y) dfs(v);
	for (int v : mp[3][y - 1])
		if (x2 >= pos[v].x && pos[v].x2 >= x) dfs(v);
}

signed main()
{
	scanf("%lld%lld%lld", &n, &stx, &sty);
	pos.push_back({0, 0, stx - 1, sty - 1});
	for (int i = 1, a, b; i <= n; i++)
	{
		char op[10];
		scanf("%s%lld%lld", op, &a, &b);
		tmp.clear();
		for (node u : pos)
		{
			if (op[0] == 'X')
			{
				if (u.x < a) tmp.push_back({u.x, u.y - b, min(u.x2, a - 1), u.y2 - b});
				if (u.x2 >= a) tmp.push_back({max(u.x, a), u.y + b, u.x2, u.y2 + b});
			}
			else
			{
				if (u.y < a) tmp.push_back({u.x - b, u.y, u.x2 - b, min(u.y2, a - 1)});
				if (u.y2 >= a) tmp.push_back({u.x + b, max(u.y, a), u.x2 + b, u.y2});
			}
		}
		pos = tmp;
	}
	for (int i = 0; i < pos.size(); i++)
	{
		mp[0][pos[i].x].push_back(i);
		mp[1][pos[i].y].push_back(i);
		mp[2][pos[i].x2].push_back(i);
		mp[3][pos[i].y2].push_back(i);
	}
	vector<int> ans;
	for (int i = 0; i < pos.size(); i++)
	{
		if (!vis[i])
		{
			res = 0;
			dfs(i);
			ans.push_back(res);
		}
	}
	sort(ans.begin(), ans.end());
	printf("%lld\n", (int)ans.size());
	for (int i : ans) printf("%lld ", i);
	return 0;
}
posted @ 2025-12-20 12:31  lucasincyber  阅读(4)  评论(0)    收藏  举报