Artwork Gym - 101550A
题目
https://cn.vjudge.net/contest/323505#problem/A
题意
给出一个m×n的矩阵,一开始全是白色,然后给出q次操作,每次将(x1,y1)到(x2,y2)这宽度为1的区域涂黑。输出每次涂黑操作后白色可以分成多少块。
题解
一开始从各种方向去想BFS的优化QAQ,后来才知道是一道并查集的题目。我们可以反向思考,先将每次涂黑的操作进行完毕,每次给涂黑的地方+1,然后把最后状态的白色块用并查集连到一起。那么我们反向删除黑色部分,当删除的这一块权值变为0时,意味着这一块从黑变成白了,那么我们先将其当作独立的一块,记录num++,然后去跑这一点的上下左右,如果两点分属不同的集合,那么num--,并且将外面的点以当前点为父亲连入。每次操作后记录下来答案,最后输出即可。学到了学到了qwq
#include <iostream> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <cstdio> #include <queue> #include <stack> #include <map> #include <bitset> #define ull unsigned long long #define met(a, b) memset(a, b, sizeof(a)) #define lowbit(x) (x&(-x)) #define MID (l + r) / 2 #define ll long long using namespace std; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f; const ll mod = 1e6 + 3; const int maxn = 1e4 + 7; const int N = 1010; struct Que { int x1, x2, y1, y2; }que[maxn]; int MAP[N][N]; int dx[] = {0, 0, -1, 1}; int dy[] = {-1, 1, 0, 0}; int f[1000100]; int vis[1000100]; int res[1000100]; int Find(int i) {return f[i] = (f[i] == i) ? f[i] : f[i] = Find(f[i]);} int main() { int n, m, q; cin >> m >> n >> q; for(int i = 1; i <= n*m+2; i++) f[i] = i; for(int i = 1; i <= q; i++) { cin >> que[i].y1 >> que[i].x1 >> que[i].y2 >> que[i].x2; if(que[i].x1 == que[i].x2) { int t1 = min(que[i].y1, que[i].y2); int t2 = max(que[i].y1, que[i].y2); for(int j = t1; j <= t2; j++) MAP[que[i].x1][j]++; } else { int t1 = min(que[i].x1, que[i].x2); int t2 = max(que[i].x1, que[i].x2); for(int j = t1; j <= t2; j++) MAP[j][que[i].y1]++; } } // for(int i = 1; i <= n; i++) { // for(int j = 1; j <= m; j++) { // cout << MAP[i][j] << ' '; // } // cout << endl; // } for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if(!MAP[i][j]) { int id = (i-1)*m+j; for(int k = 0; k < 4; k++) { int x = i+dx[k]; int y = j+dy[k]; if(x < 1 || x > n) continue; if(y < 1 || y > m) continue; if(!MAP[x][y]) { int t = (x-1)*m+y; int fi = Find(id); int fo = Find(t); f[fo] = fi; } } } } } int num = 0; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { int fi = Find((i-1)*m+j); if(!MAP[i][j] && !vis[fi]) { vis[fi] = 1; num++; } } } for(int i = q; i >= 1; i--) { res[i] = num; if(que[i].x1 == que[i].x2) { int t1 = min(que[i].y1, que[i].y2); int t2 = max(que[i].y1, que[i].y2); for(int j = t1; j <= t2; j++) { MAP[que[i].x1][j]--; if(!MAP[que[i].x1][j]) { num++; int id = (que[i].x1-1)*m+j; for(int k = 0; k < 4; k++) { int x = que[i].x1+dx[k]; int y = j+dy[k]; if(x < 1 || x > n) continue; if(y < 1 || y > m) continue; if(!MAP[x][y]) { int t = (x-1)*m+y; int fi = Find(id); int fo = Find(t); if(fi != fo) num--; f[fo] = fi; } } } } } else { int t1 = min(que[i].x1, que[i].x2); int t2 = max(que[i].x1, que[i].x2); for(int j = t1; j <= t2; j++) { MAP[j][que[i].y1]--; if(!MAP[j][que[i].y1]) { num++; int id = (j-1)*m+que[i].y1; for(int k = 0; k < 4; k++) { int x = j+dx[k]; int y = que[i].y1+dy[k]; if(x < 1 || x > n) continue; if(y < 1 || y > m) continue; if(!MAP[x][y]) { int t = (x-1)*m+y; int fi = Find(id); int fo = Find(t); if(fi != fo) num--; f[fo] = fi; } } } } } } for(int i = 1; i <= q; i++) cout << res[i] << endl; return 0; }
分类:
算法学习—并查集
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· “你见过凌晨四点的洛杉矶吗?”--《我们为什么要睡觉》
· 编程神器Trae:当我用上后,才知道自己的创造力被低估了多少
· C# 从零开始使用Layui.Wpf库开发WPF客户端
· 开发的设计和重构,为开发效率服务
· 从零开始开发一个 MCP Server!