BZOJ 1453 (线段树+并查集)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1453
题意:一个 n*n 的矩阵,每个位置有黑/白两种颜色,有 m 次操作,每次可以翻转其中一个位置的格子颜色,问每次操作后黑色和白色连通块的个数。
题解:考虑若没有翻转颜色的操作时,可以用并查集来找出两种连通块的个数,加上修改的操作,可以用线段树维护并查集的信息。对每列建线段树,合并时将边界合并,修改从叶子到根进行合并,详见代码~
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define mst(a,b) memset((a),(b),sizeof(a)) #define mp(a,b) make_pair(a,b) #define pi acos(-1) #define pii pair<int,int> #define pb push_back const int INF = 0x3f3f3f3f; const double eps = 1e-6; const int MAXN = 3e5 + 10; const int MAXM = 1e7 + 10; const ll mod = 1e9 + 7; int n, m; int s[210][210], fa[210 * 210]; int id(int x,int y) { return x * n + y; } int findd(int x) { return x == fa[x] ? x : fa[x] = findd(fa[x]); } struct node { int l[210],r[210],ans[2]; }st[210<<2]; node mergee(node &a,node &b,int mid) { node c; for(int i = 1; i <= n; i++) { c.l[i] = a.l[i], c.r[i] = b.r[i]; fa[a.l[i]] = a.l[i], fa[a.r[i]] = a.r[i]; fa[b.l[i]] = b.l[i], fa[b.r[i]] = b.r[i]; } for(int i = 0; i < 2; i++) c.ans[i] = a.ans[i] + b.ans[i]; for(int i = 1; i <= n; i++) { if(s[i][mid] == s[i][mid + 1]) { int x = findd(a.r[i]), y = findd(b.l[i]); if(x == y) continue; c.ans[s[i][mid]]--, fa[x] = y; } } for(int i = 1; i <= n; i++) { c.l[i] = findd(c.l[i]); c.r[i] = findd(c.r[i]); } return c; } void build(int rt,int l,int r) { if(l == r) { st[rt].ans[0] = st[rt].ans[1] = 0; for(int i = 1; i <= n; i++) { st[rt].l[i] = st[rt].r[i] = fa[id(i,l)] = id(i,l); st[rt].ans[s[i][l]]++; } for(int i = 2; i <= n; i++) { if(s[i][l] == s[i - 1][l]) { st[rt].l[i] = st[rt].r[i] = fa[id(i,l)] = fa[id(i - 1,l)]; st[rt].ans[s[i][l]]--; } } return ; } int mid = (l + r) >> 1; build(rt<<1,l,mid); build(rt<<1|1,mid + 1,r); st[rt] = mergee(st[rt<<1],st[rt<<1|1],mid); } void update(int rt,int l,int r,int pos) { if(l == r) { st[rt].ans[0] = st[rt].ans[1] = 0; for(int i = 1; i <= n; i++) { st[rt].l[i] = st[rt].r[i] = fa[id(i,l)] = id(i,l); st[rt].ans[s[i][l]]++; } for(int i = 2; i <= n; i++) { if(s[i][l] == s[i - 1][l]) { st[rt].l[i] = st[rt].r[i] = fa[id(i,l)] = fa[id(i - 1,l)]; st[rt].ans[s[i][l]]--; } } return ; } int mid = (l + r) >> 1; if(pos <= mid) update(rt<<1,l,mid,pos); else update(rt<<1|1,mid + 1,r,pos); st[rt] = mergee(st[rt<<1],st[rt<<1|1],mid); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif scanf("%d",&n); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d",&s[i][j]); build(1,1,n); scanf("%d",&m); while(m--) { int x,y; scanf("%d%d",&x,&y); s[x][y] ^= 1; update(1,1,n,y); printf("%d %d\n",st[1].ans[1],st[1].ans[0]); } return 0; }