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

浙公网安备 33010602011771号