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提高组模拟】随机的排列


暂时还不会...

posted @ 2020-10-09 20:13  buzzhou  阅读(206)  评论(0编辑  收藏  举报