CodeForces 1303F - Number of Components(删边并查集)

题意

一个 n ∗ m n*m nm的地图,一开始全是颜色0.
Q次询问,每次把 ( x , y ) (x,y) (x,y)的格子变成颜色 c c c。问每次操作完之后有多少个同色联通块。
保证 c i c_i ci以单调不降的顺序给出,且保证 c i ≤ m a x ( 1000 , 2 e 6 / ( n m ) ) c_i\le max(1000,2e6/(nm)) cimax(1000,2e6/(nm))

解题思路

可以按照不同的颜色分别统计。那么修改一个位置的颜色相当于在一种颜色的集合删掉一个位置,在另一个颜色的集合种加入一个位置。
因为保证 c i c_i ci是不降的,所以删除操作之后不可能出现加入操作。因此问题就转换成了对于一个图,求删掉一些边之后连通块个数。这是并查集的经典问题:删边并查集。可以把顺序的删边,想成逆序的加边。
因为删边并查集需要把没有删过的边加入,所以我们在最后存留的图里面把那些对应的颜色再加入到删除序列中,然后让他们不参与答案的统计,这样在统计答案的时候这些没有删的位置就已经在图中了。

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define fors(i, a, b) for(int i = (a); i < (b); ++i)
#define P pair<int,int>
using namespace std;
int n, m, q;
const int maxn = 2e5 + 50;
int rk[maxn], fa[maxn];
int fnd(int x){
    
    return (x == fa[x])?x:fa[x] = fnd(fa[x]);}
int link(int u, int v){
    
    
    u = fnd(u); v = fnd(v);
    if(u == v) return 0;
    if(rk[u] < rk[v]) swap(u, v);
    fa[v] = u; if(rk[u] == rk[v]) rk[u]++;
    return 1;
}
vector<int> g[maxn];
int a[maxn];
void init(){
    
    
    scanf("%d%d%d", &n, &m, &q);
    fors(i, 0, n*m) fa[i] = i;
    fors(i, 0, n) fors(j, 0, m-1) {
    
    
        int u = i*m+j, v = i*m+j+1;
        g[u].pb(v); g[v].pb(u);
    }
    fors(j, 0, m) fors(i, 0, n-1){
    
    
        int u = i*m+j, v = (i+1)*m+j;
        g[u].pb(v); g[v].pb(u);
    }
}
vector<P> add[maxn*10], del[maxn*10];
int d[maxn*10];
void work(vector<P> &c, int op){
    
    
    fors(i, 0, n) fors(j, 0, m) a[i*m+j] = 0, fa[i*m+j] = i*m+j, rk[i*m+j] = 1;

    for(auto t: c){
    
    
        int u = t.first, id = t.second;
        int cur = 1; a[u] = 1;
        for(int v: g[u]){
    
    
            if(a[v]) cur -= link(u, v);
        }
        d[id] += cur*op;
    }
}
void sol(){
    
    
    int mx = 1;
    for(int i = 0; i < q; ++i){
    
    
        int x, y, c; scanf("%d%d%d", &x, &y, &c);x--;y--;
        int u = x*m+y;
        if(c == a[u]) continue;
        mx = c+1;
        add[c].pb(P(u, i));
        del[a[u]].pb(P(u, i));
        a[u] = c;
    }
    fors(i, 0, n*m) del[a[i]].pb(P(i, q));
    fors(i, 0, mx) reverse(del[i].begin(), del[i].end());

    fors(i, 0, mx) work(add[i], 1);
    fors(i, 0, mx) work(del[i], -1);

    int ans = 1;
    fors(i, 0, q) ans += d[i], printf("%d\n", ans);
}
int main()
{
    
    
    init();
    sol();
}

猜你喜欢

转载自blog.csdn.net/qq_43202683/article/details/104321440