首页 > 其他分享 >CF750H New Year and Snowy Grid

CF750H New Year and Snowy Grid

时间:2023-02-22 07:44:05浏览次数:36  
标签:sz 连通 Snowy int top Grid New 1005 find

\(\text{Solution}\)

这个问题是不好判断的
考虑简单点的,\((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]] = '.';
    }
}

标签:sz,连通,Snowy,int,top,Grid,New,1005,find
From: https://www.cnblogs.com/leiyuanze/p/17143100.html

相关文章

  • python+playwright 学习-5.new_context上下文与新窗口操作
    前言browser.new_context()创建一个新的浏览器上下文。它不会与其他浏览器上下文共享cookies/缓存。浏览器上下文使用browser.new_context()创建context对象,context......
  • 简单理解js之ActiveX控件 new ActiveXObject
    ActiveX控件切记:ActiveX是微软的东西,故只有IE才支持!ActiveX控件,它一些可重用的软件组件或对象,通过使用ActiveX控件,可以很快地在网址、台式应用程序、以及开发工具中加入......
  • WPF datagrid双击一整行而不是选中单元格
    WPF开发一个工具需要双击datagrid的某一行显示详细数据并编辑,之前双击行(DatagridRow)每次都跳转到单元格上(DatagridCell)经验证,需要修改datagrid样式的某几个属性值 dat......
  • Java面试宝典_君哥讲解笔记04_java基础面试题——String s=new String(“xyz“);创建了
    java基础面试题目录文章目录​​java基础面试题目录​​​​前言​​​​Strings=newString("xyz");创建了几个StringObject【重要】​​​​全面理解:Strings2="xyz"......
  • 给gridview添加checkBox 并且做全选功能
    对gridview添加模板编辑模板-->显示中选择:HeaderTemplate-->把chekcBox拖进来                显示中选择:ItemTemplate-->把chekcBox拖进来 在headerTem......
  • 打开MASA Blazor的正确姿势4.3:Grid网格布局
    Grid网格布局,借鉴了Bootstrap,以Flex弹性布局为基础,使用组件方式,让我们以更加简单直接的行列方式,进行灵活布局,是MASABlazor中更加推荐的布局方式。如果已经熟悉了Flex弹......
  • QGridLayout(表格布局)
    (一)使用QGridLayout控件的思路在新建QGridLayout对象之前,应该先将在将使用到的控件进行初始化。1.初始化布局新建QGridLayout之后,在桌面上就会出现一个网格状的布局,这个......
  • CPP内存分配的详细指南——new和allocator以及智能指针
    Motivationcpp里面的内存管理一直让我头疼万分,最近重新翻了翻cppprimeplus这本书,被里面各种new搞得头皮发麻,于是就有了这篇博文。主要记录我自己对cpp里面内存管理的问......
  • 有什么区别 new 和 malloc() ?
    malloc()是一个以数字(字节)作为参数的函数;它返回一个void*指向单元化存储。new是一个运算符,它接受一个类型和(可选)该类型的一组初始值设定项作为它的论点;它返回一个......
  • new后可以用free吗
    虽然语言不会阻止您这样做,但您永远不应该在使用C++new运算符收到的块上使用Cfree函数。始终对从new运算符接收的块使用C++delete运算符,对从new[]运算符接收......