【题目链接】
【思路要点】
- 当且仅当跳蚤个数不足两个,或跳蚤个数为两个,并且他们位置相邻,答案为-1。
- 否则,当且仅当原本跳蚤中存在不连通的跳蚤,答案为0。
- 否则,当且仅当原图中存在割点,答案为1。
- 否则答案为2。
- 将整张图建出来,依次检验以上判断标准,可以得到一个时空复杂度为\(O(N*M)\)的做法。
- 我们发现\(N\)和\(M\)均很大,而\(C\)很小,这意味着存在大面积的空白,考虑只考虑周围两圈存在障碍点的位置。
- 显然上述位置的数量是\(O(C)\)的,我们在相邻的被选中的点之间对连边。
- 我们称周围一圈存在障碍点的位置为1级位置,其余被选中的位置为2级位置。
- 原图中存在不连通的跳蚤等价于新图的每个联通块(算上蛐蛐)中存在不连通的跳蚤。
- [1]若原图(\(N*M\)的图)存在割点,那么这些割点的位置必定是1级位置,而由于我们选定了所有2级位置,1级位置在原图中是割点等价于1级位置在新图中是割点。
- 在新图上运行Tarjan算法,判断是否存在割点。
- 时间复杂度\(O(\sum C)\)。
- 实现时需要特判\(N\)或\(M\)为1的情况,因为此时[1]不成立。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXP = 3000005; const int P = 1e6 + 3; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, m, k; struct HashTable { int nxt[MAXP], head[P]; int x[MAXP], y[MAXP], l[MAXP], tot; bool vis[MAXP]; void init() { for (int i = 1; i <= tot; i++) head[(x[i] * (m + 1ll) + y[i]) % P] = 0; tot = 0; } void insert(int tx, int ty, bool val, int level) { if (tx < 1 || tx > n) return; if (ty < 1 || ty > m) return; int r = (tx * (m + 1ll) + ty) % P, p = head[r]; while (p != 0) { if (x[p] == tx && y[p] == ty) { chkmin(l[p], level); return; } p = nxt[p]; } tot++; x[tot] = tx; y[tot] = ty; l[tot] = level; vis[tot] = val; nxt[tot] = head[r]; head[r] = tot; } int query(int tx, int ty) { if (tx < 1 || tx > n) return -1; if (ty < 1 || ty > m) return -1; int r = (tx * (m + 1ll) + ty) % P, p = head[r]; while (p != 0) { if (x[p] == tx && y[p] == ty) return p; p = nxt[p]; } return -1; } } HT; vector <int> a[MAXP]; int timer, dfn[MAXP], low[MAXP]; bool vis[MAXP], found; int f, g, h; void fill(int pos) { vis[pos] = true; f++; g += !HT.vis[pos]; for (unsigned i = 0; i < a[pos].size(); i++) if (!vis[a[pos][i]]) fill(a[pos][i]); } void tarjan(int pos, int fa) { h++; dfn[pos] = low[pos] = ++timer; int tmp = 0; for (unsigned i = 0; i < a[pos].size(); i++) { if (HT.vis[a[pos][i]]) continue; if (dfn[a[pos][i]] == 0) { tarjan(a[pos][i], pos); chkmin(low[pos], low[a[pos][i]]); if (fa == 0) tmp++; if (low[a[pos][i]] == dfn[pos] && fa != 0) { found |= HT.l[pos] == 1; } } else chkmin(low[pos], dfn[a[pos][i]]); } if (tmp >= 2) found |= HT.l[pos] == 1; } int main() { int T; read(T); HT.init(); while (T--) { read(n), read(m), read(k); if (k == 0) { if (n + m <= 3) printf("-1\n"); else if (n == 1 || m == 1) printf("1\n"); else printf("2\n"); continue; } if (n == 1) { static int pos[MAXP]; for (int i = 1; i <= k; i++) { int x, y; read(x), read(y); pos[i] = y; } sort(pos + 1, pos + k + 1); pos[k + 1] = m + 1; if (m - k <= 1) { printf("-1\n"); continue; } int Max = 0, cnt = 0; for (int i = 0; i <= k; i++) { chkmax(Max, pos[i + 1] - pos[i] - 1); if (pos[i + 1] - pos[i] - 1) cnt++; } if (m - k == 2 && Max == 2) { printf("-1\n"); continue; } if (cnt >= 2) { printf("0\n"); continue; } printf("1\n"); continue; } if (m == 1) { static int pos[MAXP]; for (int i = 1; i <= k; i++) { int x, y; read(x), read(y); pos[i] = x; } sort(pos + 1, pos + k + 1); pos[k + 1] = n + 1; if (n - k <= 1) { printf("-1\n"); continue; } int Max = 0, cnt = 0; for (int i = 0; i <= k; i++) { chkmax(Max, pos[i + 1] - pos[i] - 1); if (pos[i + 1] - pos[i] - 1) cnt++; } if (n - k == 2 && Max == 2) { printf("-1\n"); continue; } if (cnt >= 2) { printf("0\n"); continue; } printf("1\n"); continue; } for (int i = 1; i <= k; i++) { int x, y; read(x), read(y); HT.insert(x, y, true, 0); } if (1ll * n * m - k <= 1) { printf("-1\n"); HT.init(); continue; } if (1ll * n * m - k == 2) { int tx = 0, ty = 0, sx = 0, sy = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (HT.query(i, j) == -1) { if (tx == 0) { tx = i; ty = j; } else { sx = i; sy = j; } } } if (abs(tx - sx) + abs(ty - sy) == 1) { printf("-1\n"); HT.init(); continue; } } for (int i = 1; i <= k; i++) { int tx = HT.x[i]; int ty = HT.y[i]; for (int dx = -2; dx <= 2; dx++) for (int dy = -2; dy <= 2; dy++) { int tmp = max(abs(dx), abs(dy)); HT.insert(tx + dx, ty + dy, false, tmp); } } timer = 0; for (int i = 1; i <= HT.tot; i++) { a[i].clear(); vis[i] = false; dfn[i] = low[i] = 0; } for (int i = 1; i <= HT.tot; i++) { int tx = HT.x[i]; int ty = HT.y[i]; for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) { if (dx * dy != 0) continue; int tmp = HT.query(tx + dx, ty + dy); if (tmp != -1 && tmp != i) { a[i].push_back(tmp); } } } int ans = 2; for (int i = k + 1; i <= HT.tot; i++) { if (!vis[i]) { f = g = 0; fill(i); h = 0; found = false; tarjan(i, 0); if (h != g) chkmin(ans, 0); if (found) chkmin(ans, 1); } } printf("%d\n", ans); HT.init(); } return 0; }