CodeForces 1303F - Number of Components(刪邊並查集)

題意

一個nmn*m的地圖,一開始全是顏色0.
Q次詢問,每次把(x,y)(x,y)的格子變成顏色cc。問每次操作完之後有多少個同色聯通塊。
保證cic_i以單調不降的順序給出,且保證cimax(1000,2e6/(nm))c_i\le max(1000,2e6/(nm))

解題思路

可以按照不同的顏色分別統計。那麼修改一個位置的顏色相當於在一種顏色的集合刪掉一個位置,在另一個顏色的集合種加入一個位置。
因爲保證cic_i是不降的,所以刪除操作之後不可能出現加入操作。因此問題就轉換成了對於一個圖,求刪掉一些邊之後連通塊個數。這是並查集的經典問題:刪邊並查集。可以把順序的刪邊,想成逆序的加邊。
因爲刪邊並查集需要把沒有刪過的邊加入,所以我們在最後存留的圖裏面把那些對應的顏色再加入到刪除序列中,然後讓他們不參與答案的統計,這樣在統計答案的時候這些沒有刪的位置就已經在圖中了。

#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();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章