线段树+并查集
这道题跟codeforces #416 div2 E几乎一样 于是我又抄了一遍代码
我们建线段树,维护l->r区间这一块黑色白色连通块的数量,并且维护两端的并查集,每次合并区间就是把并查集合并,计算颜色的变化数量,并查集具体是维护一个fa数组,每次合并的时候把两端的并查集信息放到fa里,然后并查集操作是在fa上进行,线段树只是维护了一下信息。
所以cf也抄原题?
#include<bits/stdc++.h> using namespace std; const int N = 210; struct node { int l[N], r[N]; int ans[2]; } tree[N << 3]; int n, m; int fa[N * N], Map[N][N]; #define id(x, y) (x - 1) * n + y int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } node merge(const node &a, const 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(Map[i][mid] == Map[i][mid + 1]) { int u = find(a.r[i]), v = find(b.l[i]); if(u == v) continue; fa[u] = v; --c.ans[Map[i][mid]]; } for(int i = 1; i <= n; ++i) c.l[i] = find(c.l[i]), c.r[i] = find(c.r[i]); return c; } void build(int l, int r, int x) { if(l == r) { for(int i = 1; i <= n; ++i) { tree[x].l[i] = tree[x].r[i] = fa[id(i, l)] = id(i, l); ++tree[x].ans[Map[i][l]]; } for(int i = 2; i <= n; ++i) if(Map[i][l] == Map[i - 1][l]) { fa[id(i, l)] = tree[x].l[i] = tree[x].r[i] = fa[id(i - 1, l)]; --tree[x].ans[Map[i][l]]; } return; } int mid = (l + r) >> 1; build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1); tree[x] = merge(tree[x << 1], tree[x << 1 | 1], mid); } void update(int l, int r, int x, int pos) { if(l == r) { tree[x].ans[0] = tree[x].ans[1] = 0; for(int i = 1; i <= n; ++i) { tree[x].l[i] = tree[x].r[i] = fa[id(i, l)] = id(i, l); ++tree[x].ans[Map[i][l]]; } for(int i = 2; i <= n; ++i) if(Map[i][l] == Map[i - 1][l]) { fa[id(i, l)] = tree[x].l[i] = tree[x].r[i] = fa[id(i - 1, l)]; --tree[x].ans[Map[i][l]]; } return; } int mid = (l + r) >> 1; if(pos <= mid) update(l, mid, x << 1, pos); else update(mid + 1, r, x << 1 | 1, pos); tree[x] = merge(tree[x << 1], tree[x << 1 | 1], mid); } int main() { scanf("%d", &n); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) scanf("%d", &Map[i][j]); build(1, n, 1); scanf("%d", &m); while(m--) { int x, y; scanf("%d%d", &x, &y); Map[x][y] ^= 1; update(1, n, 1, y); printf("%d %d ", tree[1].ans[1], tree[1].ans[0]); } return 0; }