1. 程式人生 > 實用技巧 >2020.10.6 提高組模擬

2020.10.6 提高組模擬

2020.10.6 提高組模擬

6815. 【2020.10.06提高組模擬】樹的重心


Description

給定 \(n \times m\) 的矩陣,\((i, j)\) 的顏色為 \(s_{i,j}\)
q 次操作,每次將 \((1, 1)\) 所在的連通塊顏色替換,求每次替換後連通塊的大小。
連通塊:若 \((x, y)\)\((x', y;)\) 存在公共邊且顏色相同則在同一連通塊內。

Data Constraint

\(1 \leq n, m \leq 1000\)\(1 \leq 顏色種類數 \leq 10^6\),運算元小於等於 \(2 \times 10^5\)

Solution

只需要維護與 \((1, 1)\)

所在連通塊相連的點即可,用一個佇列維護每種顏色的點,
每次操作將與替換顏色相同的點所在的連通塊加入答案,
並把連通塊周圍未加入佇列的點加入佇列。

提前將處理出連通塊也許可以簡化操作。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>

using namespace std;

#define N 1001
#define M 1000001

#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define Fo(i, x, q) for(int i = x; i; i = q[i].next)

struct NEXT_P { int x, next; } p1[M + 1], p2[M << 2];

struct Arr { int x, y, f, siz; } fa[M << 1];

int h1[M << 1], h2[M + 1], c[N + 1][N + 1], a[N + 1][N + 1];

bitset <M << 1> used, vis;

int n, m, q, k, cnt1 = 0, cnt2 = 0, tot = 0, ans = 0;

void read(int &x) {
    char ch = getchar(); x = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
}

int Getfa(int x) { return x == fa[x].f ? x : fa[x].f = Getfa(fa[x].f); }

void Merge(int u, int v) {
    int x = Getfa(u), y = Getfa(v);
    if (x == y) return;
    fa[y].siz += fa[x].siz;
    fa[x].f = fa[y].f;
}

void Add2(int u, int v) { p2[ ++ cnt2 ] = (NEXT_P) { v, h2[u] }, h2[u] = cnt2; }
void Link(int u, int v) { Add2(u, v), Add2(v, u); }

void Add1(int col, int v) { p1[ ++ cnt1 ] = (NEXT_P) { v, h1[col] }, h1[col] = cnt1; }

int test1 = 0, test2 = 0;

void Solve(int col) {
    Fo(i, h1[col], p1) if (! used[p1[i].x]) {
        used[p1[i].x] = 1, h1[col] = p1[i].next;
        ans += fa[p1[i].x].siz;

        Fo(j, h2[p1[i].x], p2) if (! vis[p2[j].x])
            Add1(c[fa[p2[j].x].x][fa[p2[j].x].y], p2[j].x), vis[p2[j].x] = 1;
    }
}

int main() {
    freopen("color.in", "r", stdin);
    freopen("color.out", "w", stdout);

    read(n), read(m), read(q), read(k);
    fo(i, 1, n) fo(j, 1, m) read(c[i][j]);

    fo(i, 1, n) fo(j, 1, m) fa[ a[i][j] = ++ tot ] = (Arr) { i, j, tot, 1 };
    fo(i, 1, n) fo(j, 1, m) {
        if (i > 1 && c[i - 1][j] == c[i][j])
            Merge(a[i][j], a[i - 1][j]);
        if (j > 1 && c[i][j - 1] == c[i][j])
            Merge(a[i][j], a[i][j - 1]);
    }
    fo(i, 1, n) fo(j, 1, m) {
        if (i > 1 && c[i - 1][j] != c[i][j])
            Link(Getfa(a[i - 1][j]), Getfa(a[i][j]));
        if (j > 1 && c[i][j - 1] != c[i][j])
            Link(Getfa(a[i][j - 1]), Getfa(a[i][j]));
    }
    used.reset(), vis.reset();
    Add1(c[1][1], Getfa(a[1][1]));
    vis[Getfa(a[1][1])] = 1;
    Solve(c[1][1]);
    int x;
    fo(OPT, 1, q) {
        read(x);
        Solve(x);
        printf("%d\n", ans);
    }

    return 0;
}

6815.【2020.10.06提高組模擬】樹的重心


Description & Solution

6816. 【2020.10.06提高組模擬】隨機的排列


暫時還不會...