bzoj1453

线段树+并查集

这道题跟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;
}
View Code
原文地址:https://www.cnblogs.com/19992147orz/p/7597323.html