CF750H New Year and Snowy Grid
阅读原文时间:2023年07月08日阅读:1

这个问题是不好判断的

考虑简单点的,\((1,1)\) 到 \((h,w)\) 是否连通

那么只要在最外围一圈 #(显然一些位置不能加),判断 \((h+1,n)\) 和 \((0,w+1)\) 是否能通过 # 八连通即可

如果是双连通呢?只要这两点所在连通块不能通过只加一个 # 就连通

看起来很不可做的题猜测一些简单结论就很可做了

判断否就考虑加一个 # 就连通的位置,这个 # 必然是连接了两个连通块

考虑这两个连通块的类别,一是新填的两个 #,O(k^2) 枚举即可

二是连接了原图中的两个连通块,这两个连通块又通过新的 # 连通了 \((h+1,n)\) 或 \((0,w+1)\)

于是把所有这样的连通块记录下来,判断两两是否在原图中只加一个 # 就连通

三是一个新 # 和原图中的连通块,发现处理可以和二一样

判断两连通块是否只加一个 # 就连通可以用哈希表预处理

一次询问是临时的,可撤销并查集即可

\(\text{Code}\)

#include <bits/stdc++.h>
#define IN inline
#define eb emplace_back
using namespace std;

int n, m, q, id[1005][1005];
char str[1005], mp[1005][1005];

const int N = 1e6 + 5e3;
struct DSU {
    int fa[N], sz[N], top;
    struct Edge{int u, v;}stk[N];
    IN int find(int x){while (fa[x] != x) x = fa[x]; return x;}
    IN void merge(int x, int y) {
        int u = find(x), v = find(y);
        if (u == v) return; if (sz[u] > sz[v]) swap(u, v);
        fa[u] = v, sz[v] += sz[u], stk[++top] = Edge{u, v};
    }
    IN void clear(int lst) {
        for(int u, v; top != lst; --top)
            u = stk[top].u, v = stk[top].v, sz[v] -= sz[u], fa[u] = u;
    }
}T1, T2;

int fx[9][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, 1}, {-1, -1}, {1, -1}, {-1, 1}};
unordered_map<int, int> hs[N];

void dfs(int x, int y, int d, int p) {
    if ((x == 2 && y == 2) || (x == n - 1 && y == m - 1)) return;
    if (mp[x][y] == '#') hs[p][T1.find(id[x][y])] = 1;
    if (!d) return;
    for(int k = 0; k < 8; k++) {
        int xx = x + fx[k][0], yy = y + fx[k][1];
        if (id[xx][yy]) dfs(xx, yy, d - 1, p);
    }
}

void Init() {
    scanf("%d%d%d", &n, &m, &q), n += 2, m += 2;
    for(int i = 2; i < n; i++) scanf("%s", mp[i] + 2);
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) id[i][j] = (i - 1) * m + j;
    for(int j = 1; j <= m; j++) mp[1][j] = mp[n][j] = '#';
    for(int i = 1; i <= n; i++) mp[i][1] = mp[i][m] = '#';
    mp[1][1] = mp[1][2] = mp[2][1] = mp[n - 1][m] = mp[n][m - 1] = mp[n][m] = '.';
    for(int i = 1; i <= n * m; i++) T1.fa[i] = i, T1.sz[i] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) if (mp[i][j] == '#')
            for(int k = 0; k < 8; k++) {
                int x = i + fx[k][0], y = j + fx[k][1];
                if (id[x][y] && mp[x][y] == '#') T1.merge(id[i][j], id[x][y]);
            }
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) dfs(i, j, 2, T1.find(id[i][j]));
    for(int i = 1; i <= n * m; i++) T2.fa[i] = T1.fa[i], T2.sz[i] = T1.sz[i];
}

int X[15], Y[15];

int main() {
    Init();
    for(; q; --q) {
        int K; scanf("%d", &K);
        for(int i = 1; i <= K; i++) scanf("%d%d", &X[i], &Y[i]), mp[++X[i]][++Y[i]] = '#';
        int lst = T2.top;
        for(int i = 1; i <= K; i++)
                for(int k = 0; k < 8; k++) {
                    int x = X[i] + fx[k][0], y = Y[i] + fx[k][1];
                    if (id[x][y] && mp[x][y] == '#') T2.merge(id[X[i]][Y[i]], id[x][y]);
                }
        int flag = 0;
        for(int i = 1; i <= K && !flag; i++)
            for(int j = 1; j <= K; j++) if (max(abs(X[i] - X[j]), abs(Y[i] - Y[j])) <= 2) {
                if (T2.find(id[X[i]][Y[i]]) == T2.find(id[1][m]) && T2.find(id[X[j]][Y[j]]) == T2.find(id[n][1])) {
                    flag = 1; break;
                }
            }
        vector<int> Vr, Vl; Vr.eb(T1.find(id[1][m])), Vl.eb(T1.find(id[n][1]));
        for(int i = 1; i <= K; i++) {
            for(int k = 0; k <= 8; k++) {
                int x = X[i] + fx[k][0], y = Y[i] + fx[k][1];
                if (id[x][y] && T2.find(id[x][y]) == T2.find(id[1][m])) Vr.eb(T1.find(id[x][y]));
                if (id[x][y] && T2.find(id[x][y]) == T2.find(id[n][1])) Vl.eb(T1.find(id[x][y]));
            }
        }
        for(auto kr : Vr) for(auto kl : Vl)
            if (hs[kr].find(kl) != hs[kr].end() || hs[kl].find(kr) != hs[kl].end()){flag = 1; break;}
        if (!flag) puts("YES"); else puts("NO"); fflush(stdout);
        T2.clear(lst); for(int i = 1; i <= K; i++) mp[X[i]][Y[i]] = '.';
    }
}