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

猜你喜欢

转载自www.cnblogs.com/scaulok/p/9888054.html