2020.10.6 提高组模拟
6815. 【2020.10.06提高组模拟】树的重心
Description
给定 (n imes 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 imes 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
", ans);
}
return 0;
}
6815.【2020.10.06提高组模拟】树的重心
Description & Solution
6816. 【2020.10.06提高组模拟】随机的排列
暂时还不会...