1. 程式人生 > >BZOJ 1453 線段樹+並查集

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