Problem:
Remodeling the Dungeon 2
The Queen of the Kingdom of
Icpca
resides in a castle peacefully. One day, she decided to remodel the dungeon of the castle.
The dungeonis a rectangular grid consisting of square cells. Some cells are enterable rooms, while others are duct spaces which are not enterable. All pairs of adjacent cells are separated by a wall. Some of the walls between two adjacent rooms are installed with a door to go back and forth. Any pair of rooms in the dungeon has connecting paths through these doors.
The Queen wants to remodel the dungeon so that there is only one unique path between any pair of rooms. Additionally, any pair of rooms both with only one door should be connected with a path going through an even number of doors. Due to the cost limitation, what can be done in the remodeling is only to block some (possibly zero) doors.
Your mission is to find a way to remodel the dungeon as the Queen wants.
Input
The input consists of a single test case in the following format.
$h$ $w$
$c_{1,1}c_{1,2}$ ... $c_{1,2w+1}$
$c_{2,1}c_{2,2}$ ... $c_{2,2w+1}$
$\vdots$
$c_{2h+1,1}c_{2h+1,2}$ ... $c_{2h+1,2w+1}$
Two integers $h$ and $w$ mean that the dungeon size is $h \times w$. They are between 1 and 400, inclusive.
Each of the characters $c_{i,j}$ ($1 \leq i \leq 2h + 1, 1 \leq j \leq 2w + 1$) is either ‘
.
’ or ‘
#
’. These characters represent the configuration of the dungeon as follows.
When both $i$ and $j$ are even, $c_{i,j}$ represents the cell located at the $i/2$-th row from the north and the $j/2$-th column from the west of the dungeon, referred to as cell ($i/2,j/2$). Being ‘
.
’ indicates that the cell is a room, while ‘
#
’ indicates a duct space.
When $i$ is odd and $j$ is even, it represents a wall. When $i = 1$ or $i = 2h+1$, it is a part of the outer wall of the dungeon. In this case, $c_{i,j}$ is always ‘
#
’. Otherwise, $c_{i,j}$ represents the wall between cells ($(i − 1)/2,j/2$) and ($(i + 1)/2,j/2$). Being ‘
.
’ indicates that the wall has a door, while ‘
#
’ indicates that it does not. Doors are installed only in walls between two rooms.
When $i$ is even and $j$ is odd, it also represents a wall. When $j = 1$ or $j = 2w + 1$, it is a part of the outer wall of the dungeon. In this case, $c_{i,j}$ is always ‘
#
’. Otherwise, $c_{i,j}$ represents the wall between cells ($i/2,(j − 1)/2$) and ($i/2,(j + 1)/2$). Being ‘
.
’ indicates that the wall has a door, while ‘
#
’ indicates that it does not. Doors are installed only in walls between two rooms.
When both $i$ and $j$ are odd, $c_{i,j}$ is always ‘
#
’, corresponding to an intersection of walls.
It is guaranteed that there is at least one room in the dungeon and any pair of rooms in the dungeon has one or more connecting paths.
Output
If it is impossible to remodel the dungeon as the Queen wants, output
No
. Otherwise, output
Yes
on the first line, followed by the configuration of the dungeon after the remodeling in the same format as the input. If there are multiple possib
...(truncated)

Submitted solutions:

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using i64 = long long;
using u64 = unsigned long long;
#define rep(i,n) for(int i=0; i<int(n); i++)
const i64 INF = 1001001001001001001;
template<typename A> void chmin(A& l, const A& r){ if(r < l) l = r; }
template<typename A> void chmax(A& l, const A& r){ if(l < r) l = r; }
using namespace std;
#include <utility>

namespace nachia{

template<class Elem>
class CsrArray{
public:
    struct ListRange{
        using iterator = typename std::vector<Elem>::iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        Elem& operator[](int i) const { return begi[i]; }
    };
    struct ConstListRange{
        using iterator = typename std::vector<Elem>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const Elem& operator[](int i) const { return begi[i]; }
    };
private:
    int m_n;
    std::vector<Elem> m_list;
    std::vector<int> m_pos;
public:
    CsrArray() : m_n(0), m_list(), m_pos() {}
    static CsrArray Construct(int n, std::vector<std::pair<int, Elem>> items){
        CsrArray res;
        res.m_n = n;
        std::vector<int> buf(n+1, 0);
        for(auto& [u,v] : items){ ++buf[u]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.m_list.resize(buf[n]);
        for(int i=(int)items.size()-1; i>=0; i--){
            res.m_list[--buf[items[i].first]] = std::move(items[i].second);
        }
        res.m_pos = std::move(buf);
        return res;
    }
    static CsrArray FromRaw(std::vector<Elem> list, std::vector<int> pos){
        CsrArray res;
        res.m_n = pos.size() - 1;
        res.m_list = std::move(list);
        res.m_pos = std::move(pos);
        return res;
    }
    ListRange operator[](int u) { return ListRange{ m_list.begin() + m_pos[u], m_list.begin() + m_pos[u+1] }; }
    ConstListRange operator[](int u) const { return ConstListRange{ m_list.begin() + m_pos[u], m_list.begin() + m_pos[u+1] }; }
    int size() const { return m_n; }
    int fullSize() const { return (int)m_list.size(); }
};

} // namespace nachia

namespace nachia{

std::vector<int> BipertiteMatching(int N1, int N2, const std::vector<std::pair<int, int>>& edges){
    std::vector<int> R(N2, -1);
    std::vector<int> L(N1, -1);
    auto E = CsrArray<int>::Construct(N1, edges);
    while(true){
        std::vector<int> bfs, dist(N1, -1), P(N1, -1);
        for(int i=0; i<N1; i++) if(L[i] == -1){ bfs.push_back(i); dist[i] = 0; }
        int maxD = N1 + 1;
        for(size_t i=0; i<bfs.size(); i++){
            int p = bfs[i];
            if(dist[p] >= maxD) break;
            for(int e : E[p]) if(L[p] != e){
                if(R[e] >= 0){
                    if(dist[R[e]] < 0){
                        dist[R[e]] = dist[p] + 1;
                        P[R[e]] = p;
                        bfs.push_back(R[e]);
                    }
                }
                else maxD = dist[p];
            }
        }
        if(maxD > N1) break;
        std::vector<int> I(N1, 0);
        for(int s=0; s<N1; s++) if(L[s] == -1){
            int p = s, p2;
            while(p >= 0){
                if(I[p] == E[p].size()){ p = P[p]; continue; }
                int q = E[p][I[p]++];
                int r = R[q];
                if(r == -1){ p2 = q; break; }
                if(dist[r] != dist[p] + 1) continue;
                P[r] = p;
                p = r;
            }
            if(p < 0) continue;
            while(p >= 0){
                R[p2] = p;
                std::swap(L[p], p2);
                p = P[p];
            }
        }
    }
    std::vector<int> ans;
    for(int i=0; i<(int)edges.size(); i++){
        auto& e = edges[i];
        if(L[e.first] == e.second){ L[e.first] = -1; ans.push_back(i); }
    }
    return ans;
}

} // namespace nachia
#include <cassert>

namespace nachia{


struct Graph {
public:
    struct Edge{
        int from, to;
        void reverse(){ std::swap(from, to); }
        int xorval() const { return from ^ to; }
    };
    Graph() : m_n(0), m_e(0), m_isUndir(false) {}
    explicit Graph(int n, bool undirected = false, int m = 0) : m_n(n), m_e(m), m_isUndir(undirected) {}
    explicit Graph(int n, const std::vector<std::pair<int, int>>& edges, int undirected = false) : m_n(n), m_isUndir(undirected){
        m_e.resize(edges.size());
        for(std::size_t i=0; i<edges.size(); i++) m_e[i] = { edges[i].first, edges[i].second };
    }
    template<class Cin>
    static Graph Input(Cin& cin, int n, bool undirected, int m, int offset = 0){
        Graph res(n, undirected, m);
        for(int i=0; i<m; i++){
            int u, v; cin >> u >> v;
            res[i].from = u - offset;
            res[i].to = v - offset;
        }
        return res;
    }
    int numVertices() const noexcept { return m_n; }
    int numEdges() const noexcept { return int(m_e.size()); }
    int addNode() noexcept { return m_n++; }
    int addEdge(int from, int to){ m_e.push_back({ from, to }); return numEdges() - 1; }
    Edge& operator[](int ei) noexcept { return m_e[ei]; }
    const Edge& operator[](int ei) const noexcept { return m_e[ei]; }
    Edge& at(int ei) { return m_e.at(ei); }
    const Edge& at(int ei) const { return m_e.at(ei); }
    auto begin(){ return m_e.begin(); }
    auto end(){ return m_e.end(); }
    auto begin() const { return m_e.begin(); }
    auto end() const { return m_e.end(); }
    bool isUndirected() const noexcept { return m_isUndir; }
    void reverseEdges() noexcept { for(auto& e : m_e) e.reverse(); }
    void contract(int newV, const std::vector<int>& mapping){
        assert(numVertices() == int(mapping.size()));
        for(int i=0; i<numVertices(); i++) assert(0 <= mapping[i] && mapping[i] < newV);
        for(auto& e : m_e){ e.from = mapping[e.from]; e.to = mapping[e.to]; }
        m_n = newV;
    }
    std::vector<Graph> induce(int num, const std::vector<int>& mapping) const {
        int n = numVertices();
        assert(n == int(mapping.size()));
        for(int i=0; i<n; i++) assert(-1 <= mapping[i] && mapping[i] < num);
        std::vector<int> indexV(n), newV(num);
        for(int i=0; i<n; i++) if(mapping[i] >= 0) indexV[i] = newV[mapping[i]]++;
        std::vector<Graph> res; res.reserve(num);
        for(int i=0; i<num; i++) res.emplace_back(newV[i], isUndirected());
        for(auto e : m_e) if(mapping[e.from] == mapping[e.to] && mapping[e.to] >= 0) res[mapping[e.to]].addEdge(indexV[e.from], indexV[e.to]);
        return res;
    }
    CsrArray<int> getEdgeIndexArray(bool undirected) const {
        std::vector<std::pair<int, int>> src;
        src.reserve(numEdges() * (undirected ? 2 : 1));
        for(int i=0; i<numEdges(); i++){
            auto e = operator[](i);
            src.emplace_back(e.from, i);
            if(undirected) src.emplace_back(e.to, i);
        }
        return CsrArray<int>::Construct(numVertices(), src);
    }
    CsrArray<int> getEdgeIndexArray() const { return getEdgeIndexArray(isUndirected()); }
    CsrArray<int> getAdjacencyArray(bool undirected) const {
        std::vector<std::pair<int, int>> src;
        src.reserve(numEdges() * (undirected ? 2 : 1));
        for(auto e : m_e){
            src.emplace_back(e.from, e.to);
            if(undirected) src.emplace_back(e.to, e.from);
        }
        return CsrArray<int>::Construct(numVertices(), src);
    }
    CsrArray<int> getAdjacencyArray() const { return getAdjacencyArray(isUndirected()); }
private:
    int m_n;
    std::vector<Edge> m_e;
    bool m_isUndir;
};

} // namespace nachia


vector<pair<int,int>> ConstructionOfATree(
    int N,
    int M,
    vector<vector<int>> E
){
    //cout << endl;
    //rep(i,M){
    //    cout << E[i].size();
    //    for(auto v : E[i]) cout << " " << (v+1);
    //    cout << endl;
    //}
    //cout << endl;
    vector<int> matching(M); {
        vector<pair<int,int>> edges;
        rep(i,M) for(int e : E[i]) edges.push_back({ i, e });
        auto matchbuf = nachia::BipertiteMatching(M, N, edges);
        if(int(matchbuf.size()) != M) return {};
        for(int e : matchbuf) matching[edges[e].first] = edges[e].second;
    }
    //cout << "##" << endl;

    vector<int> matched(N);
    rep(i,M) matched[matching[i]] = 1;
    vector<int> roots;
    rep(i,N) if(matched[i] == 0) roots.push_back(i);

    //cout << "roots : ";
    //for(auto root : roots) cout << root << " ";
    //cout << endl;

    auto graph = nachia::Graph(N, false);
    rep(i,M){
        int v = matching[i];
        for(int e : E[i]) if(e != v) graph.addEdge(e, v);
    }
    vector<int> parent(N, -1);
    vector<int> bfs;
    int bfsi = 0;
   // cout << "##" << endl;


    for(int root : roots){
        bfs.push_back(root);
        parent[root] = -2;
        auto adj = graph.getAdjacencyArray();
        for( ; bfsi<int(bfs.size()); bfsi++){
            int v = bfs[bfsi];
            for(int w : adj[v]) if(parent[w] == -1){
                parent[w] = v;
                bfs.push_back(w);
            }
        }
    }
    if(int(bfs.size()) != N){ return {}; }
    vector<pair<int,int>> res(M);
    rep(i,M){
        res[i] = { matching[i], parent[matching[i]] };
    }
    return res;
}


namespace nachia {

struct DsuFast{
private:
    std::vector<int> w;
public:
    DsuFast(int n = 0) : w(n, -1) {}
    int leader(int u){
        if(w[u] < 0) return u;
        return w[u] = leader(w[u]);
    }
    int operator[](int u){ return leader(u); }
    int merge(int u, int v){
        u = leader(u);
        v = leader(v);
        if(u == v) return u;
        if(-w[u] < -w[v]) std::swap(u, v);
        w[u] += w[v];
        w[v] = u;
        return u;
    }
    int size(int u){ return -w[leader(u)]; }
    bool same(int u, int v){ return leader(u) == leader(v); }
};

} // namespace nachia

void testcase(){
    int H, W; cin >> H >> W;
    vector<string> A(H*2+1); rep(y,H*2+1) cin >> A[y];
    int cnt[2] = {};
    rep(y,H) rep(x,W) if(A[y*2+1][x*2+1] == '.') cnt[(y+x)%2]++;
    if(cnt[0] == cnt[1]){ cout << "No\n"; return; }
    int way = cnt[0] < cnt[1] ? 0 : 1;
    vector<vector<int>> idx(H, vector<int>(W, -1)); {
        int idxi = 0;
        rep(y,H) rep(x,W) if(A[y*2+1][x*2+1] == '.' && (x+y)%2 == way) idx[y][x] = idxi++;
        rep(y,H) rep(x,W) if(A[y*2+1][x*2+1] == '.' && (x+y)%2 != way) idx[y][x] = idxi++;
    }
    //rep(y,H){
    //    rep(x,W) cout << idx[y][x] << " ";
    //    cout << endl;
    //}
    vector<vector<int>> edges(cnt[way]);
    auto addEdge = [&](int u, int v){
        if(u == -1 || v == -1) return;
        if(u < cnt[way]) edges[u].push_back(v - cnt[way]);
        else edges[v].push_back(u - cnt[way]);
    };
    rep(y,H) rep(x,W-1) if(A[y*2+1][x*2+2] == '.') addEdge(idx[y][x], idx[y][x+1]);
    rep(y,H-1) rep(x,W) if(A[y*2+2][x*2+1] == '.') addEdge(idx[y][x], idx[y+1][x]);
    auto tre = ConstructionOfATree(cnt[way^1], cnt[way], edges);
    //for(auto [u,v] : tre){
    //    cout << u << " " << v << endl;
    //}
    if(tre.empty() && cnt[way] != 0){ cout << "No\n"; return; }

   // cout << "##" << endl;

    auto dsu = nachia::DsuFast(cnt[0] + cnt[1]);
    vector<pair<int,int>> Q;
    auto checkEdge = [&](int u, int v){
        if(u > v) swap(u,v);
        if(dsu.same(u,v)) return;
        dsu.merge(u,v);
        Q.push_back({u,v});
    };

    //cout << "##" << endl;

    rep(i,cnt[way]){
        checkEdge(i, tre[i].first + cnt[way]);
        checkEdge(i, tre[i].second + cnt[way]);
    }
    rep(y,H) rep(x,W-1) if(A[y*2+1][x*2+2] == '.') checkEdge(idx[y][x], idx[y][x+1]);
    rep(y,H-1) rep(x,W) if(A[y*2+2][x*2+1] == '.') checkEdge(idx[y][x], idx[y+1][x]);

    //cout << "##" << endl;

    if(Q.size() != cnt[0] + cnt[1] - 1){
        cout << "No\n";
        return;
    }

    sort(Q.begin(), Q.end());
    auto hasEdge = [&](int u, int v){
        if(u > v) swap(u,v);
        return binary_search(Q.begin(), Q.end(), make_pair(u,v));
    };

    rep(y,H) rep(x,W-1) if(!hasEdge(idx[y][x], idx[y][x+1])) A[y*2+1][x*2+2] = '#';
    rep(y,H-1) rep(x,W) if(!hasEdge(idx[y][x], idx[y+1][x])) A[y*2+2][x*2+1] = '#';
    cout << "Yes\n";
    rep(y,H*2+1) cout << A[y] << "\n";
}

int main(){
    ios::sync_with_stdio(false); cin.tie(nullptr);
    testcase();
    return 0;
}
accuracy: 1
time_ms: 930
memory_kb: 21724
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
using pint = pair<int,int>;

// Union-Find
struct UnionFind {
    // core member
    vector<int> par, nex;

    // constructor
    UnionFind() { }
    UnionFind(int N) : par(N, -1), nex(N) {
        init(N);
    }
    void init(int N) {
        par.assign(N, -1);
        nex.resize(N);
        for (int i = 0; i < N; ++i) nex[i] = i;
    }
    
    // core methods
    int root(int x) {
        if (par[x] < 0) return x;
        else return par[x] = root(par[x]);
    }
    
    bool same(int x, int y) {
        return root(x) == root(y);
    }
    
    bool merge(int x, int y) {
        x = root(x), y = root(y);
        if (x == y) return false;
        if (par[x] > par[y]) swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        swap(nex[x], nex[y]);
        return true;
    }
    
    int size(int x) {
        return -par[root(x)];
    }
    
    // get group
    vector<int> group(int x) {
        vector<int> res({x});
        while (nex[res.back()] != x) res.push_back(nex[res.back()]);
        return res;
    }
    vector<vector<int>> groups() {
        vector<vector<int>> member(par.size());
        for (int v = 0; v < (int)par.size(); ++v) {
            member[root(v)].push_back(v);
        }
        vector<vector<int>> res;
        for (int v = 0; v < (int)par.size(); ++v) {
            if (!member[v].empty()) res.push_back(member[v]);
        }
        return res;
    }
    
    // debug
    friend ostream& operator << (ostream &s, UnionFind uf) {
        const vector<vector<int>> &gs = uf.groups();
        for (const vector<int> &g : gs) {
            s << "group: ";
            for (int v : g) s << v << " ";
            s << endl;
        }
        return s;
    }
};

// edge class (for network-flow)
template<class FLOWTYPE> struct FlowEdge {
    // core members
    int rev, from, to;
    FLOWTYPE cap, icap, flow;
    
    // constructor
    FlowEdge(int r, int f, int t, FLOWTYPE c)
    : rev(r), from(f), to(t), cap(c), icap(c), flow(0) {}
    void reset() { cap = icap, flow = 0; }
    
    // debug
    friend ostream& operator << (ostream& s, const FlowEdge& E) {
        return s << E.from << "->" << E.to << '(' << E.flow << '/' << E.icap << ')';
    }
};

// graph class (for network-flow)
template<class FLOWTYPE> struct FlowGraph {
    // core members
    vector<vector<FlowEdge<FLOWTYPE>>> list;
    vector<pair<int,int>> pos;  // pos[i] := {vertex, order of list[vertex]} of i-th edge
    
    // constructor
    FlowGraph(int n = 0) : list(n) { }
    void init(int n = 0) {
        list.assign(n, FlowEdge<FLOWTYPE>());
        pos.clear();
    }
    
    // getter
    vector<FlowEdge<FLOWTYPE>> &operator [] (int i) {
        return list[i];
    }
    const vector<FlowEdge<FLOWTYPE>> &operator [] (int i) const {
        return list[i];
    }
    size_t size() const {
        return list.size();
    }
    FlowEdge<FLOWTYPE> &get_rev_edge(const FlowEdge<FLOWTYPE> &e) {
        if (e.from != e.to) return list[e.to][e.rev];
        else return list[e.to][e.rev + 1];
    }
    FlowEdge<FLOWTYPE> &get_edge(int i) {
        return list[pos[i].first][pos[i].second];
    }
    const FlowEdge<FLOWTYPE> &get_edge(int i) const {
        return list[pos[i].first][pos[i].second];
    }
    vector<FlowEdge<FLOWTYPE>> get_edges() const {
        vector<FlowEdge<FLOWTYPE>> edges;
        for (int i = 0; i < (int)pos.size(); ++i) {
            edges.push_back(get_edge(i));
        }
        return edges;
    }
    
    // change edges
    void reset() {
        for (int i = 0; i < (int)list.size(); ++i) {
            for (FlowEdge<FLOWTYPE> &e : list[i]) e.reset();
        }
    }
    void change_edge(FlowEdge<FLOWTYPE> &e, FLOWTYPE new_cap, FLOWTYPE new_flow) {
        FlowEdge<FLOWTYPE> &re = get_rev_edge(e);
        e.cap = new_cap - new_flow, e.icap = new_cap, e.flow = new_flow;
        re.cap = new_flow;
    }
    
    // add_edge
    void add_edge(int from, int to, FLOWTYPE cap) {
        pos.emplace_back(from, (int)list[from].size());
        list[from].push_back(FlowEdge<FLOWTYPE>((int)list[to].size(), from, to, cap));
        list[to].push_back(FlowEdge<FLOWTYPE>((int)list[from].size() - 1, to, from, 0));
    }

    // debug
    friend ostream& operator << (ostream& s, const FlowGraph &G) {
        const auto &edges = G.get_edges();
        for (const auto &e : edges) s << e << endl;
        return s;
    }
};

// Dinic
template<class FLOWTYPE> FLOWTYPE Dinic
 (FlowGraph<FLOWTYPE> &G, int s, int t, FLOWTYPE limit_flow)
{
    FLOWTYPE current_flow = 0;
    vector<int> level((int)G.size(), -1), iter((int)G.size(), 0);
    
    // Dinic BFS
    auto bfs = [&]() -> void {
        level.assign((int)G.size(), -1);
        level[s] = 0;
        queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop();
            for (const FlowEdge<FLOWTYPE> &e : G[v]) {
                if (level[e.to] < 0 && e.cap > 0) {
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.push(e.to);
                }
            }
        }
    };
    
    // Dinic DFS
    auto dfs = [&](auto self, int v, FLOWTYPE up_flow) {
        if (v == t) return up_flow;
        FLOWTYPE res_flow = 0;
        for (int &i = iter[v]; i < (int)G[v].size(); ++i) {
            FlowEdge<FLOWTYPE> &e = G[v][i], &re = G.get_rev_edge(e);
            if (level[v] >= level[e.to] || e.cap == 0) continue;
            FLOWTYPE flow = self(self, e.to, min(up_flow - res_flow, e.cap));
            if (flow <= 0) continue;
            res_flow += flow;
            e.cap -= flow, e.flow += flow;
            re.cap += flow, re.flow -= flow;
            if (res_flow == up_flow) break;
        }
        return res_flow;
    };
    
    // flow
    while (current_flow < limit_flow) {
        bfs();
        if (level[t] < 0) break;
        iter.assign((int)iter.size(), 0);
        while (current_flow < limit_flow) {
            FLOWTYPE flow = dfs(dfs, s, limit_flow - current_flow);
            if (!flow) break;
            current_flow += flow;
        }
    }
    return current_flow;
};

template<class FLOWTYPE> FLOWTYPE Dinic(FlowGraph<FLOWTYPE> &G, int s, int t) {
    return Dinic(G, s, t, numeric_limits<FLOWTYPE>::max());
}

// 4-neighbor
const vector<int> dx = {1, 0, -1, 0};
const vector<int> dy = {0, 1, 0, -1};


int main() {
    // 入力
    int H, W;
    cin >> H >> W;
    vector<string> field(H * 2 + 1), res(H * 2 + 1, string(W * 2 + 1, '#'));
    vector<bool> seen(H * W, true);
    int even = 0, odd = 0;
    for (int i = 0; i < H * 2 + 1; i++) {
        cin >> field[i];
        if (i % 2 == 1) {
            int x = i / 2;
            for (int j = 1; j < W * 2 + 1; j += 2) {
                int y = j / 2;
                if (field[i][j] == '.') {
                    res[i][j] = '.';
                    seen[x * W + y] = false;
                    if ((x + y) % 2 == 0) even++;
                    else odd++;
                }
            }
        }
    }
    if (even == odd) {
        cout << "No" << endl;
        return 0;
    }

    // 二部マッチング
    FlowGraph<int> G(H * W + 2);
    int s = H * W, t = H * W + 1;
    set<int> leftnode, rightnode;
    vector<pint> edges;
    for (int x = 0; x < H; x++) {
        for (int y = 0; y < W; y++) {
            int i = x * 2 + 1, j = y * 2 + 1, v = x * W + y;
            if (seen[v]) continue;
            bool iseven = ((x + y) % 2 == 0);
            if (even > odd && iseven) {
                G.add_edge(v, t, 1);
                rightnode.insert(v);
                continue;
            }
            if (even < odd && !iseven) {
                G.add_edge(v, t, 1);
                rightnode.insert(v);
                continue;
            };
            G.add_edge(s, v, 1);
            leftnode.insert(v);
            for (int d = 0; d < 4; d++) {
                int x2 = x + dx[d], y2 = y + dy[d], i2 = i + dx[d], j2 = j + dy[d];
                if (x2 < 0 || x2 >= H || y2 < 0 || y2 >= W) continue;
                int left = x * W + y, right = x2 * W + y2;
                if (field[i2][j2] == '.') {
                    edges.emplace_back(left, right);
                    G.add_edge(left, right, 1);
                }
            }
        }
    }
    int maxflow = Dinic(G, s, t);
    if (maxflow < leftnode.size()) {
        cout << "No" << endl;
        return 0;
    }

    // マッチングに使われていない頂点から DFS
    vector<int> start, matched(H * W, -1);
    for (auto v : leftnode) {
        for (auto e : G[v]) {
            if (e.to != s && e.flow == 1) {
                matched[e.from] = e.to;
                matched[e.to] = e.from;
            }
        }
    }
    for (auto v : rightnode) {
        if (matched[v] == -1) start.emplace_back(v);
    }
    UnionFind uf(H * W);
    vector<pint> res_edges;
    auto rec = [&](auto rec, int v) -> void {
        seen[v] = true;
        if (leftnode.count(v)) {
            int to = matched[v];
            if (to == -1 || seen[to]) return;
            res_edges.emplace_back(v, to);
            uf.merge(v, to);
            rec(rec, to);
        }
        if (rightnode.count(v)) {
            for (auto e : G[v]) {
                if (e.to == matched[v] || e.to == t || seen[e.to]) continue;
                res_edges.emplace_back(v, e.to);
                uf.merge(v, e.to);
                rec(rec, e.to);
            }
        }
    };
    for (auto v : start) {
        rec(rec, v);
    }

    // もし行き渡っていない頂点があったら No
    for (int v = 0; v < H * W; v++) {
        if (!seen[v]) {
            cout << "No" << endl;
            return 0;
        }
    }

    // 連結にする
    for (auto [u, v] : edges) {
        if (!uf.same(u, v)) {
            res_edges.emplace_back(u, v);
            uf.merge(u, v);
        }
    }

    // 答えを作る
    for (auto [u, v] : res_edges) {
        int ui = (u / W) * 2 + 1, uj = (u % W) * 2 + 1;
        int vi = (v / W) * 2 + 1, vj = (v % W) * 2 + 1;
        int mi = (ui + vi) / 2, mj = (uj + vj) / 2;
        res[mi][mj] = '.';
    }
    cout << "Yes" << endl;
    for (auto str : res) cout << str << endl;
}
accuracy: 1
time_ms: 2000
memory_kb: 90788
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using pint = pair<int,int>;

#define DEBUG 1
#define COUT(x) if (DEBUG) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, deque<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T> ostream& operator << (ostream &s, set<T> P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T> ostream& operator << (ostream &s, multiset<T> P)
{ for (auto it : P) { s << "<" << it << "> "; } return s; }
template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)
{ for (auto it : P) { s << "<" << it.first << "->" << it.second << "> "; } return s; }

// Union-Find
struct UnionFind {
    // core member
    vector<int> par, nex;

    // constructor
    UnionFind() { }
    UnionFind(int N) : par(N, -1), nex(N) {
        init(N);
    }
    void init(int N) {
        par.assign(N, -1);
        nex.resize(N);
        for (int i = 0; i < N; ++i) nex[i] = i;
    }
    
    // core methods
    int root(int x) {
        if (par[x] < 0) return x;
        else return par[x] = root(par[x]);
    }
    
    bool same(int x, int y) {
        return root(x) == root(y);
    }
    
    bool merge(int x, int y) {
        x = root(x), y = root(y);
        if (x == y) return false;
        if (par[x] > par[y]) swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        swap(nex[x], nex[y]);
        return true;
    }
    
    int size(int x) {
        return -par[root(x)];
    }
    
    // get group
    vector<int> group(int x) {
        vector<int> res({x});
        while (nex[res.back()] != x) res.push_back(nex[res.back()]);
        return res;
    }
    vector<vector<int>> groups() {
        vector<vector<int>> member(par.size());
        for (int v = 0; v < (int)par.size(); ++v) {
            member[root(v)].push_back(v);
        }
        vector<vector<int>> res;
        for (int v = 0; v < (int)par.size(); ++v) {
            if (!member[v].empty()) res.push_back(member[v]);
        }
        return res;
    }
    
    // debug
    friend ostream& operator << (ostream &s, UnionFind uf) {
        const vector<vector<int>> &gs = uf.groups();
        for (const vector<int> &g : gs) {
            s << "group: ";
            for (int v : g) s << v << " ";
            s << endl;
        }
        return s;
    }
};

// edge class (for network-flow)
template<class FLOWTYPE> struct FlowEdge {
    // core members
    int rev, from, to;
    FLOWTYPE cap, icap, flow;
    
    // constructor
    FlowEdge(int r, int f, int t, FLOWTYPE c)
    : rev(r), from(f), to(t), cap(c), icap(c), flow(0) {}
    void reset() { cap = icap, flow = 0; }
    
    // debug
    friend ostream& operator << (ostream& s, const FlowEdge& E) {
        return s << E.from << "->" << E.to << '(' << E.flow << '/' << E.icap << ')';
    }
};

// graph class (for network-flow)
template<class FLOWTYPE> struct FlowGraph {
    // core members
    vector<vector<FlowEdge<FLOWTYPE>>> list;
    vector<pair<int,int>> pos;  // pos[i] := {vertex, order of list[vertex]} of i-th edge
    
    // constructor
    FlowGraph(int n = 0) : list(n) { }
    void init(int n = 0) {
        list.assign(n, FlowEdge<FLOWTYPE>());
        pos.clear();
    }
    
    // getter
    vector<FlowEdge<FLOWTYPE>> &operator [] (int i) {
        return list[i];
    }
    const vector<FlowEdge<FLOWTYPE>> &operator [] (int i) const {
        return list[i];
    }
    size_t size() const {
        return list.size();
    }
    FlowEdge<FLOWTYPE> &get_rev_edge(const FlowEdge<FLOWTYPE> &e) {
        if (e.from != e.to) return list[e.to][e.rev];
        else return list[e.to][e.rev + 1];
    }
    FlowEdge<FLOWTYPE> &get_edge(int i) {
        return list[pos[i].first][pos[i].second];
    }
    const FlowEdge<FLOWTYPE> &get_edge(int i) const {
        return list[pos[i].first][pos[i].second];
    }
    vector<FlowEdge<FLOWTYPE>> get_edges() const {
        vector<FlowEdge<FLOWTYPE>> edges;
        for (int i = 0; i < (int)pos.size(); ++i) {
            edges.push_back(get_edge(i));
        }
        return edges;
    }
    
    // change edges
    void reset() {
        for (int i = 0; i < (int)list.size(); ++i) {
            for (FlowEdge<FLOWTYPE> &e : list[i]) e.reset();
        }
    }
    void change_edge(FlowEdge<FLOWTYPE> &e, FLOWTYPE new_cap, FLOWTYPE new_flow) {
        FlowEdge<FLOWTYPE> &re = get_rev_edge(e);
        e.cap = new_cap - new_flow, e.icap = new_cap, e.flow = new_flow;
        re.cap = new_flow;
    }
    
    // add_edge
    void add_edge(int from, int to, FLOWTYPE cap) {
        pos.emplace_back(from, (int)list[from].size());
        list[from].push_back(FlowEdge<FLOWTYPE>((int)list[to].size(), from, to, cap));
        list[to].push_back(FlowEdge<FLOWTYPE>((int)list[from].size() - 1, to, from, 0));
    }

    // debug
    friend ostream& operator << (ostream& s, const FlowGraph &G) {
        const auto &edges = G.get_edges();
        for (const auto &e : edges) s << e << endl;
        return s;
    }
};

// Dinic
template<class FLOWTYPE> FLOWTYPE Dinic
 (FlowGraph<FLOWTYPE> &G, int s, int t, FLOWTYPE limit_flow)
{
    FLOWTYPE current_flow = 0;
    vector<int> level((int)G.size(), -1), iter((int)G.size(), 0);
    
    // Dinic BFS
    auto bfs = [&]() -> void {
        level.assign((int)G.size(), -1);
        level[s] = 0;
        queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int v = que.front();
            que.pop();
            for (const FlowEdge<FLOWTYPE> &e : G[v]) {
                if (level[e.to] < 0 && e.cap > 0) {
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.push(e.to);
                }
            }
        }
    };
    
    // Dinic DFS
    auto dfs = [&](auto self, int v, FLOWTYPE up_flow) {
        if (v == t) return up_flow;
        FLOWTYPE res_flow = 0;
        for (int &i = iter[v]; i < (int)G[v].size(); ++i) {
            FlowEdge<FLOWTYPE> &e = G[v][i], &re = G.get_rev_edge(e);
            if (level[v] >= level[e.to] || e.cap == 0) continue;
            FLOWTYPE flow = self(self, e.to, min(up_flow - res_flow, e.cap));
            if (flow <= 0) continue;
            res_flow += flow;
            e.cap -= flow, e.flow += flow;
            re.cap += flow, re.flow -= flow;
            if (res_flow == up_flow) break;
        }
        return res_flow;
    };
    
    // flow
    while (current_flow < limit_flow) {
        bfs();
        if (level[t] < 0) break;
        iter.assign((int)iter.size(), 0);
        while (current_flow < limit_flow) {
            FLOWTYPE flow = dfs(dfs, s, limit_flow - current_flow);
            if (!flow) break;
            current_flow += flow;
        }
    }
    return current_flow;
};

template<class FLOWTYPE> FLOWTYPE Dinic(FlowGraph<FLOWTYPE> &G, int s, int t) {
    return Dinic(G, s, t, numeric_limits<FLOWTYPE>::max());
}

// 4-neighbor
const vector<int> dx = {1, 0, -1, 0};
const vector<int> dy = {0, 1, 0, -1};

int main() {
    // 入力
    int H, W;
    cin >> H >> W;
    vector<string> field(H * 2 + 1), res(H * 2 + 1, string(W * 2 + 1, '#'));
    vector<bool> seen(H * W, true);
    int even = 0, odd = 0;
    for (int i = 0; i < H * 2 + 1; i++) {
        cin >> field[i];
        if (i % 2 == 1) {
            int x = i / 2;
            for (int j = 1; j < W * 2 + 1; j += 2) {
                int y = j / 2;
                if (field[i][j] == '.') {
                    res[i][j] = '.';
                    seen[x * W + y] = false;
                    if ((x + y) % 2 == 0) even++;
                    else odd++;
                }
            }
        }
    }
    if (even == odd) {
        cout << "No" << endl;
        return 0;
    }

    // 二部マッチング
    FlowGraph<int> G(H * W + 2);
    int s = H * W, t = H * W + 1;
    set<int> leftnode, rightnode;
    vector<pint> edges;
    for (int x = 0; x < H; x++) {
        for (int y = 0; y < W; y++) {
            int i = x * 2 + 1, j = y * 2 + 1, v = x * W + y;
            if (seen[v]) continue;
            bool iseven = ((x + y) % 2 == 0);
            if (even > odd && iseven) {
                G.add_edge(v, t, 1);
                rightnode.insert(v);
                continue;
            }
            if (even < odd && !iseven) {
                G.add_edge(v, t, 1);
                rightnode.insert(v);
                continue;
            };
            G.add_edge(s, v, 1);
            leftnode.insert(v);
            for (int d = 0; d < 4; d++) {
                int x2 = x + dx[d], y2 = y + dy[d], i2 = i + dx[d], j2 = j + dy[d];
                if (x2 < 0 || x2 >= H || y2 < 0 || y2 >= W) continue;
                int left = x * W + y, right = x2 * W + y2;
                if (field[i2][j2] == '.') {
                    edges.emplace_back(left, right);
                    G.add_edge(left, right, 1);
                }
            }
        }
    }

    //COUT(G);

    int maxflow = Dinic(G, s, t);

    //COUT(leftnode); COUT(rightnode); COUT(maxflow);

    if (maxflow < leftnode.size()) {
        cout << "No" << endl;
        return 0;
    }
    //COUT(leftnode); COUT(rightnode); COUT(maxflow);

    // マッチングに使われていない頂点から DFS
    vector<int> start, matched(H * W, -1);
    for (auto v : leftnode) {
        for (auto e : G[v]) {
            if (e.to != s && e.flow == 1) {
                matched[e.from] = e.to;
                matched[e.to] = e.from;
            }
        }
    }
    for (auto v : rightnode) {
        if (matched[v] == -1) start.emplace_back(v);
    }
    UnionFind uf(H * W);

    //COUT(start);

    vector<pint> res_edges;
    auto rec = [&](auto rec, int v) -> void {
        seen[v] = true;
        if (leftnode.count(v)) {
            int to = matched[v];
            if (to == -1 || seen[to]) return;
            res_edges.emplace_back(v, to);
            uf.merge(v, to);
            rec(rec, to);
        }
        if (rightnode.count(v)) {
            for (auto e : G[v]) {
                if (e.to == matched[v] || e.to == t || seen[e.to]) continue;
                res_edges.emplace_back(v, e.to);
                uf.merge(v, e.to);
                rec(rec, e.to);
            }
        }
    };
    for (auto v : start) {
        rec(rec, v);
    }

    // もし行き渡っていない頂点があったら No
    for (int v = 0; v < H * W; v++) {
        if (!seen[v]) {
            cout << "No" << endl;
            return 0;
        }
    }

    // 連結にする
    for (auto [u, v] : edges) {
        if (!uf.same(u, v)) {
            res_edges.emplace_back(u, v);
            uf.merge(u, v);
        }
    }

    // 答えを作る
    for (auto [u, v] : res_edges) {
        int ui = (u / W) * 2 + 1, uj = (u % W) * 2 + 1;
        int vi = (v / W) * 2 + 1, vj = (v % W) * 2 + 1;
        int mi = (ui + vi) / 2, mj = (uj + vj) / 2;
        res[mi][mj] = '.';
    }
    cout << "Yes" << endl;
    for (auto str : res) cout << str << endl;
}
accuracy: 1
time_ms: 2330
memory_kb: 99528
final_rank: 6

code_snippet: //#define _GLIBCXX_DEBUG

//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")

#include<bits/stdc++.h>
using namespace std;


#ifdef LOCAL
#include <debug_print.hpp>
#define OUT(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__)
#else
#define OUT(...) (static_cast<void>(0))
#endif

#define endl '\n'
#define lfs cout<<fixed<<setprecision(15)
#define ALL(a)  (a).begin(),(a).end()
#define ALLR(a)  (a).rbegin(),(a).rend()
#define UNIQUE(a) (a).erase(unique((a).begin(),(a).end()),(a).end())
#define spa << " " <<
#define fi first
#define se second
#define MP make_pair
#define MT make_tuple
#define PB push_back
#define EB emplace_back
#define rep(i,n,m) for(ll i = (n); i < (ll)(m); i++)
#define rrep(i,n,m) for(ll i = (ll)(m) - 1; i >= (ll)(n); i--)

namespace template_tute{
  using ll = long long;
  using ld = long double;
  const ll MOD1 = 1e9+7;
  const ll MOD9 = 998244353;
  const ll INF = 4.1e18;
  using P = pair<ll, ll>;
  template<typename T> using PQ = priority_queue<T>;
  template<typename T> using QP = priority_queue<T,vector<T>,greater<T>>;
  template<typename T1, typename T2>bool chmin(T1 &a,T2 b){if(a>b){a=b;return true;}else return false;}
  template<typename T1, typename T2>bool chmax(T1 &a,T2 b){if(a<b){a=b;return true;}else return false;}
  ll median(ll a,ll b, ll c){return a+b+c-max<ll>({a,b,c})-min<ll>({a,b,c});}
  void ans1(bool x){if(x) cout<<"Yes"<<endl;else cout<<"No"<<endl;}
  void ans2(bool x){if(x) cout<<"YES"<<endl;else cout<<"NO"<<endl;}
  void ans3(bool x){if(x) cout<<"Yay!"<<endl;else cout<<":("<<endl;}
  template<typename T1,typename T2>void ans(bool x,T1 y,T2 z){if(x)cout<<y<<endl;else cout<<z<<endl;}  
  template<typename T1,typename T2,typename T3>void anss(T1 x,T2 y,T3 z){ans(x!=y,x,z);};  
  template<typename T>void debug(const T &v,ll h,ll w,string sv=" "){for(ll i=0;i<h;i++){cout<<v[i][0];for(ll j=1;j<w;j++)cout<<sv<<v[i][j];cout<<endl;}};
  template<typename T>void debug(const T &v,ll n,string sv=" "){if(n!=0)cout<<v[0];for(ll i=1;i<n;i++)cout<<sv<<v[i];cout<<endl;};
  template<typename T>void debug(const vector<T>&v){debug(v,v.size());}
  template<typename T>void debug(const vector<vector<T>>&v){for(auto &vv:v)debug(vv,vv.size());}
  template<typename T>void debug(stack<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
  template<typename T>void debug(queue<T> st){while(!st.empty()){cout<<st.front()<<" ";st.pop();}cout<<endl;}
  template<typename T>void debug(deque<T> st){while(!st.empty()){cout<<st.front()<<" ";st.pop_front();}cout<<endl;}
  template<typename T>void debug(PQ<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
  template<typename T>void debug(QP<T> st){while(!st.empty()){cout<<st.top()<<" ";st.pop();}cout<<endl;}
  template<typename T>void debug(const set<T>&v){for(auto z:v)cout<<z<<" ";cout<<endl;}
  template<typename T>void debug(const multiset<T>&v){for(auto z:v)cout<<z<<" ";cout<<endl;}
  template<typename T,size_t size>void debug(const array<T, size> &a){for(auto z:a)cout<<z<<" ";cout<<endl;}
  template<typename T,typename V>void debug(const map<T,V>&v){for(auto z:v)cout<<"["<<z.first<<"]="<<z.second<<",";cout<<endl;}
  template<typename T>vector<vector<T>>vec(ll x, ll y, T w){vector<vector<T>>v(x,vector<T>(y,w));return v;}
  vector<ll>dx={1,-1,0,0,1,1,-1,-1};vector<ll>dy={0,0,1,-1,1,-1,1,-1};
  template<typename T>vector<T> make_v(size_t a,T b){return vector<T>(a,b);}
  template<typename... Ts>auto make_v(size_t a,Ts... ts){return vector<decltype(make_v(ts...))>(a,make_v(ts...));}
  template<typename T1, typename T2>ostream &operator<<(ostream &os, const pair<T1, T2>&p){return os << "(" << p.first << "," << p.second << ")";}
  template<typename T>ostream &operator<<(ostream &os, const vector<T> &v){os<<"[";for(auto &z:v)os << z << ",";os<<"]"; return os;}
  template<typename T>void rearrange(vector<int>&ord, vector<T>&v){
    auto tmp = v;
    for(int i=0;i<tmp.size();i++)v[i] = tmp[ord[i]];
  }
  template<typename Head, typename... Tail>void rearrange(vector<int>&ord,Head&& head, Tail&&... tail){
    rearrange(ord, head);
    rearrange(ord, tail...);
  }
  template<typename T> vector<int> ascend(const vector<T>&v){
    vector<int>ord(v.size());iota(ord.begin(),ord.end(),0);
    sort(ord.begin(),ord.end(),[&](int i,int j){return make_pair(v[i],i)<make_pair(v[j],j);});
    return ord;
  }
  template<typename T> vector<int> descend(const vector<T>&v){
    vector<int>ord(v.size());iota(ord.begin(),ord.end(),0);
    sort(ord.begin(),ord.end(),[&](int i,int j){return make_pair(v[i],-i)>make_pair(v[j],-j);});
    return ord;
  }
  template<typename T> vector<T> inv_perm(const vector<T>&ord){
    vector<T>inv(ord.size());
    for(int i=0;i<ord.size();i++)inv[ord[i]] = i;
    return inv;
  }
  ll FLOOR(ll n,ll div){assert(div>0);return n>=0?n/div:(n-div+1)/div;}
  ll CEIL(ll n,ll div){assert(div>0);return n>=0?(n+div-1)/div:n/div;}
  ll digitsum(ll n){ll ret=0;while(n){ret+=n%10;n/=10;}return ret;}
  ll modulo(ll n,ll d){return (n%d+d)%d;};
  template<typename T>T min(const vector<T>&v){return *min_element(v.begin(),v.end());}
  template<typename T>T max(const vector<T>&v){return *max_element(v.begin(),v.end());}
  template<typename T>T acc(const vector<T>&v){return accumulate(v.begin(),v.end(),T(0));};
  template<typename T>T reverse(const T &v){return T(v.rbegin(),v.rend());};
  //mt19937 mt(chrono::steady_clock::now().time_since_epoch().count());
  int popcount(ll x){return __builtin_popcountll(x);};
  int poplow(ll x){return __builtin_ctzll(x);};
  int pophigh(ll x){return 63 - __builtin_clzll(x);};
  template<typename T>T poll(queue<T> &q){auto ret=q.front();q.pop();return ret;};
  template<typename T>T poll(priority_queue<T> &q){auto ret=q.top();q.pop();return ret;};
  template<typename T>T poll(QP<T> &q){auto ret=q.top();q.pop();return ret;};
  template<typename T>T poll(stack<T> &s){auto ret=s.top();s.pop();return ret;};
  ll MULT(ll x,ll y){if(LLONG_MAX/x<=y)return LLONG_MAX;return x*y;}
  ll POW2(ll x, ll k){ll ret=1,mul=x;while(k){if(mul==LLONG_MAX)return LLONG_MAX;if(k&1)ret=MULT(ret,mul);mul=MULT(mul,mul);k>>=1;}return ret;}
  ll POW(ll x, ll k){ll ret=1;for(int i=0;i<k;i++){if(LLONG_MAX/x<=ret)return LLONG_MAX;ret*=x;}return ret;}
  std::ostream &operator<<(std::ostream &dest, __int128_t value) {
    std::ostream::sentry s(dest);
    if (s) {
      __uint128_t tmp = value < 0 ? -value : value;
      char buffer[128];
      char *d = std::end(buffer);
      do {
        --d;
        *d = "0123456789"[tmp % 10];
        tmp /= 10;
      } while (tmp != 0);
      if (value < 0) {
        --d;
        *d = '-';
      }
      int len = std::end(buffer) - d;
      if (dest.rdbuf()->sputn(d, len) != len) {
        dest.setstate(std::ios_base::badbit);
      }
    }
    return dest;
  }
  namespace converter{
    int dict[500];
    const string lower="abcdefghijklmnopqrstuvwxyz";
    const string upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const string digit="0123456789";
    const string digit1="123456789";
    void regi_str(const string &t){
      for(int i=0;i<t.size();i++){
        dict[t[i]]=i;
      }
    }
    void regi_int(const string &t){
      for(int i=0;i<t.size();i++){
        dict[i]=t[i];
      }
    }
    vector<int>to_int(const string &s,const string &t){
      regi_str(t);
      vector<int>ret(s.size());
      for(int i=0;i<s.size();i++){
        ret[i]=dict[s[i]];
      }
      return ret;
    }
    vector<int>to_int(const string &s){
      auto t=s;
      sort(t.begin(),t.end());
      t.erase(unique(t.begin(),t.end()),t.end());
      return to_int(s,t);
    }
    
    vector<vector<int>>to_int(const vector<string>&s,const string &t){
      regi_str(t);
      vector<vector<int>>ret(s.size(),vector<int>(s[0].size()));
      for(int i=0;i<s.size();i++){
        for(int j=0;j<s[0].size();j++){
          ret[i][j]=dict[s[i][j]];
        }
      }
      return ret;
    }
    vector<vector<int>>to_int(const vector<string>&s){
      string t;
      for(int i=0;i<s.size();i++){
        t+=s[i];
      }
      sort(t.begin(),t.end());t.erase(unique(t.begin(),t.end()),t.end());
      return to_int(s,t);
    }
    string to_str(const vector<int>&s,const string &t){
      regi_int(t);
      string ret;
      for(auto z:s)ret+=dict[z];
      return ret;
    }
    vector<string> to_str(const vector<vector<int>>&s,const string &t){
      regi_int(t);
      vector<string>ret(s.size());
      for(int i=0;i<s.size();i++){
        for(auto z:s[i])ret[i]+=dict[z];
      }
      return ret;
    }
  }
  template< typename T = int >
  struct edge {
    int to;
    T cost;
    int id;
    edge():to(-1),id(-1){};
    edge(int to, T cost = 1, int id = -1):to(to), cost(cost), id(id){}
    operator int() const { return to; }
  };

  template<typename T>
  using Graph = vector<vector<edge<T>>>;
  template<typename T>
  Graph<T>revgraph(const Graph<T> &g){
    Graph<T>ret(g.size());
    for(int i=0;i<g.size();i++){
      for(auto e:g[i]){
        int to = e.to;
        e.to = i;
        ret[to].push_back(e);
      }
    }
    return ret;
  }
  template<typename T>
  Graph<T> readGraph(int n,int m,int indexed=1,bool directed=false,bool weighted=false){
    Graph<T> ret(n);
    for(int es = 0; es < m; es++){
      int u,v;
      T w=1;
      cin>>u>>v;u-=indexed,v-=indexed;
      if(weighted)cin>>w;
      ret[u].emplace_back(v,w,es);
      if(!directed)ret[v].emplace_back(u,w,es);
    }
    return ret;
  }
  template<typename T>
  Graph<T> readParent(int n,int indexed=1,bool directed=true){
    Graph<T>ret(n);
    for(int i=1;i<n;i++){
      int p;cin>>p;
      p-=indexed;
      ret[p].emplace_back(i);
      if(!directed)ret[i].emplace_back(p);
    }
    return ret;
  }
}
using namespace template_tute;

struct UnionFind {
  vector<ll> data;
  ll num;
  UnionFind(ll size) : data(size, -1) ,num(size){ }
  bool unite(int x, int y) {
    x = root(x); y = root(y);
    if (x != y) {
      if (data[y] < data[x]) swap(x, y);
      data[x] += data[y]; data[y] = x;
    num--;
    }
    return x != y;
  }
  bool find(int x, int y) {
    return root(x) == root(y);
  }
  int root(int x) {
    return data[x] < 0 ? x : data[x] = root(data[x]);
  }
  ll size(int x) {
    return -data[root(x)];
  }
  vector<vector<int>>groups(){
    vector<vector<int>>ret(data.size());
    for(int i=0;i<data.size();i++){
      ret[root(i)].push_back(i);
    }
    return ret;
  }
  void print(){
    auto tmp=groups();
    for(int i=0;i<data.size();i++){
      if(!tmp[i].empty()){
        for(auto z:tmp[i])cout<<z<<",";
        cout<<endl;
      }
    }
  }
};

struct HopcroftKarp {
  vector< vector< int > > graph;
  vector< int > dist, match;
  vector< bool > used, vv;

  HopcroftKarp(int n, int m) : graph(n), match(m, -1), used(n) {}

  void add_edge(int u, int v) {
    graph[u].push_back(v);
  }

  void bfs() {
    dist.assign(graph.size(), -1);
    queue< int > que;
    for(int i = 0; i < graph.size(); i++) {
      if(!used[i]) {
        que.emplace(i);
        dist[i] = 0;
      }
    }

    while(!que.empty()) {
      int a = que.front();
      que.pop();
      for(auto &b : graph[a]) {
        int c = match[b];
        if(c >= 0 && dist[c] == -1) {
          dist[c] = dist[a] + 1;
          que.emplace(c);
        }
      }
    }
  }

  bool dfs(int a) {
    vv[a] = true;
    for(auto &b : graph[a]) {
      int c = match[b];
      if(c < 0 || (!vv[c] && dist[c] == dist[a] + 1 && dfs(c))) {
        match[b] = a;
        used[a] = true;
        return (true);
      }
    }
    return (false);
  }

  int bipartite_matching() {
    int ret = 0;
    while(true) {
      bfs();
      vv.assign(graph.size(), false);
      int flow = 0;
      for(int i = 0; i < graph.size(); i++) {
        if(!used[i] && dfs(i)) ++flow;
      }
      if(flow == 0) return (ret);
      ret += flow;
    }
  }

  void output() {
    for(int i = 0; i < match.size(); i++) {
      if(~match[i]) {
        cout << match[i] << "-" << i << endl;
      }
    }
  }
  vector<pair<int,int>>recover(){
    vector<pair<int,int>>ret;
    for(int i = 0; i < match.size(); i++) {
      if(~match[i]) {
        ret.emplace_back(match[i],i);
      }
    }
    return ret;
  }
};

void solve(){
	ll res=0,buf=0;
  bool judge = true;
  int h,w;cin>>h>>w;
  vector<string>s(2*h+1);
  rep(i,0,2*h+1){
    cin>>s[i];
    //s[i]=string(2*w+1,'.');
  }
  rep(pt,0,2){
    vector<pair<int,int>>epos;
    vector<pair<int,int>>edges;
    int ecnt=0;
    vector<vector<int>>grp;
    auto t=s;
    ll vercnt=0,ver2cnt=0;
    map<pair<int,int>,int>epi;
    rep(i,0,h)rep(j,0,w){
      int pi=2*i+1,pj=2*j+1;
      if(s[pi][pj]=='#'){
        continue;
      }
      if((i+j)%2!=pt){
        ver2cnt++;
        continue;
      }
      vector<int>vs;
      vercnt++;
      rep(o,0,4){
        int ei=pi+dx[o],ej=pj+dy[o];
        int ni=i+dx[o],nj=j+dy[o];
        if(s[ei][ej]=='#')continue;
        if(ni<0||nj<0||ni>=h||nj>=w)continue;
        t[ei][ej]='#';
        vs.PB(ecnt);
        epos.PB({ei,ej});
        edges.PB({i*w+j,ni*w+nj});
        epi[minmax<ll>(i*w+j,ni*w+nj)]=ecnt;
        ecnt++;
      }
      grp.PB(vs);
    }
    if(vercnt>=ver2cnt){
      continue;
    }
    HopcroftKarp hop(h*w,h*w);
    for(auto [u,v]:edges){
      hop.add_edge(u,v);
    }
    ll mmx=hop.bipartite_matching();
    if(mmx!=vercnt){
      continue;
    }
    auto match=hop.recover();
    vector<bool>used(h*w);
    vector<int>matched(h*w,-1);
    queue<int>que;
    Graph<int>g(h*w);
    for(auto e:edges){
      g[e.se].EB(e.fi);
    }
    //OUT(match,matched);
    for(auto [u,v]:match){
      matched[v]=u;
      matched[u]=v;
    }
    //OUT(match,matched);

    rep(i,0,h)rep(j,0,w){
      if((i+j)%2==pt){
        continue;
      }
      OUT(i,j,matched[i*w+j]);
      if(matched[i*w+j]==-1){
        que.push(i*w+j);
        used[i*w+j]=true;
      }
    }
    //OUT(que);
    ll sum=0;
    UnionFind uf(h*w);
    auto adder=[&](int u,int v){
      uf.unite(u,v);
      sum++;
      int ei=epi[minmax<ll>(u,v)];
      t[epos[ei].fi][epos[ei].se]='.';
      //OUT(u,v,sum);
    };
    //OUT(match,matched);
    while(!que.empty()){
      auto v=poll(que);
      for(auto to:g[v]){
        if(used[to]||matched[v]==to){
          continue;
        }
        used[to]=true;
        adder(v,to);
        adder(to,matched[to]);
        if(!used[matched[to]]){
          used[matched[to]]=true;
          que.push(matched[to]);
        }
      }
    }
    if(sum!=vercnt*2){
      continue;
    }
    cout<<"Yes"<<endl;
    rep(i,0,ecnt){
      if(uf.unite(edges[i].first,edges[i].second)){
        t[epos[i].first][epos[i].second]='.';
      }
    }
    rep(i,0,2*h+1){
      cout<<t[i]<<endl;
    }
    return;
  }
  cout<<"No"<<endl;
}

int main(){
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  ll res=0,buf=0;
  bool judge = true;
  int T = 1;
  //cin>>T;
  while(T--){
    solve();
  }
  return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 56364
final_rank: 3

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#else
#define NDEBUG
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using i64 = long long;
using u64 = unsigned long long;
#define rep(i,n) for(int i=0; i<int(n); i++)
const i64 INF = 1001001001001001001;
template<typename A> void chmin(A& l, const A& r){ if(r < l) l = r; }
template<typename A> void chmax(A& l, const A& r){ if(l < r) l = r; }
using namespace std;
#include <utility>

namespace nachia{

template<class Elem>
class CsrArray{
public:
    struct ListRange{
        using iterator = typename std::vector<Elem>::iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        Elem& operator[](int i) const { return begi[i]; }
    };
    struct ConstListRange{
        using iterator = typename std::vector<Elem>::const_iterator;
        iterator begi, endi;
        iterator begin() const { return begi; }
        iterator end() const { return endi; }
        int size() const { return (int)std::distance(begi, endi); }
        const Elem& operator[](int i) const { return begi[i]; }
    };
private:
    int m_n;
    std::vector<Elem> m_list;
    std::vector<int> m_pos;
public:
    CsrArray() : m_n(0), m_list(), m_pos() {}
    static CsrArray Construct(int n, std::vector<std::pair<int, Elem>> items){
        CsrArray res;
        res.m_n = n;
        std::vector<int> buf(n+1, 0);
        for(auto& [u,v] : items){ ++buf[u]; }
        for(int i=1; i<=n; i++) buf[i] += buf[i-1];
        res.m_list.resize(buf[n]);
        for(int i=(int)items.size()-1; i>=0; i--){
            res.m_list[--buf[items[i].first]] = std::move(items[i].second);
        }
        res.m_pos = std::move(buf);
        return res;
    }
    static CsrArray FromRaw(std::vector<Elem> list, std::vector<int> pos){
        CsrArray res;
        res.m_n = pos.size() - 1;
        res.m_list = std::move(list);
        res.m_pos = std::move(pos);
        return res;
    }
    ListRange operator[](int u) { return ListRange{ m_list.begin() + m_pos[u], m_list.begin() + m_pos[u+1] }; }
    ConstListRange operator[](int u) const { return ConstListRange{ m_list.begin() + m_pos[u], m_list.begin() + m_pos[u+1] }; }
    int size() const { return m_n; }
    int fullSize() const { return (int)m_list.size(); }
};

} // namespace nachia

namespace nachia{

std::vector<int> BipertiteMatching(int N1, int N2, const std::vector<std::pair<int, int>>& edges){
    std::vector<int> R(N2, -1);
    std::vector<int> L(N1, -1);
    auto E = CsrArray<int>::Construct(N1, edges);
    while(true){
        std::vector<int> bfs, dist(N1, -1), P(N1, -1);
        for(int i=0; i<N1; i++) if(L[i] == -1){ bfs.push_back(i); dist[i] = 0; }
        int maxD = N1 + 1;
        for(size_t i=0; i<bfs.size(); i++){
            int p = bfs[i];
            if(dist[p] >= maxD) break;
            for(int e : E[p]) if(L[p] != e){
                if(R[e] >= 0){
                    if(dist[R[e]] < 0){
                        dist[R[e]] = dist[p] + 1;
                        P[R[e]] = p;
                        bfs.push_back(R[e]);
                    }
                }
                else maxD = dist[p];
            }
        }
        if(maxD > N1) break;
        std::vector<int> I(N1, 0);
        for(int s=0; s<N1; s++) if(L[s] == -1){
            int p = s, p2;
            while(p >= 0){
                if(I[p] == E[p].size()){ p = P[p]; continue; }
                int q = E[p][I[p]++];
                int r = R[q];
                if(r == -1){ p2 = q; break; }
                if(dist[r] != dist[p] + 1) continue;
                P[r] = p;
                p = r;
            }
            if(p < 0) continue;
            while(p >= 0){
                R[p2] = p;
                std::swap(L[p], p2);
                p = P[p];
            }
        }
    }
    std::vector<int> ans;
    for(int i=0; i<(int)edges.size(); i++){
        auto& e = edges[i];
        if(L[e.first] == e.second){ L[e.first] = -1; ans.push_back(i); }
    }
    return ans;
}

} // namespace nachia
#include <cassert>

namespace nachia{


struct Graph {
public:
    struct Edge{
        int from, to;
        void reverse(){ std::swap(from, to); }
        int xorval() const { return from ^ to; }
    };
    Graph() : m_n(0), m_e(0), m_isUndir(false) {}
    explicit Graph(int n, bool undirected = false, int m = 0) : m_n(n), m_e(m), m_isUndir(undirected) {}
    explicit Graph(int n, const std::vector<std::pair<int, int>>& edges, int undirected = false) : m_n(n), m_isUndir(undirected){
        m_e.resize(edges.size());
        for(std::size_t i=0; i<edges.size(); i++) m_e[i] = { edges[i].first, edges[i].second };
    }
    template<class Cin>
    static Graph Input(Cin& cin, int n, bool undirected, int m, int offset = 0){
        Graph res(n, undirected, m);
        for(int i=0; i<m; i++){
            int u, v; cin >> u >> v;
            res[i].from = u - offset;
            res[i].to = v - offset;
        }
        return res;
    }
    int numVertices() const noexcept { return m_n; }
    int numEdges() const noexcept { return int(m_e.size()); }
    int addNode() noexcept { return m_n++; }
    int addEdge(int from, int to){ m_e.push_back({ from, to }); return numEdges() - 1; }
    Edge& operator[](int ei) noexcept { return m_e[ei]; }
    const Edge& operator[](int ei) const noexcept { return m_e[ei]; }
    Edge& at(int ei) { return m_e.at(ei); }
    const Edge& at(int ei) const { return m_e.at(ei); }
    auto begin(){ return m_e.begin(); }
    auto end(){ return m_e.end(); }
    auto begin() const { return m_e.begin(); }
    auto end() const { return m_e.end(); }
    bool isUndirected() const noexcept { return m_isUndir; }
    void reverseEdges() noexcept { for(auto& e : m_e) e.reverse(); }
    void contract(int newV, const std::vector<int>& mapping){
        assert(numVertices() == int(mapping.size()));
        for(int i=0; i<numVertices(); i++) assert(0 <= mapping[i] && mapping[i] < newV);
        for(auto& e : m_e){ e.from = mapping[e.from]; e.to = mapping[e.to]; }
        m_n = newV;
    }
    std::vector<Graph> induce(int num, const std::vector<int>& mapping) const {
        int n = numVertices();
        assert(n == int(mapping.size()));
        for(int i=0; i<n; i++) assert(-1 <= mapping[i] && mapping[i] < num);
        std::vector<int> indexV(n), newV(num);
        for(int i=0; i<n; i++) if(mapping[i] >= 0) indexV[i] = newV[mapping[i]]++;
        std::vector<Graph> res; res.reserve(num);
        for(int i=0; i<num; i++) res.emplace_back(newV[i], isUndirected());
        for(auto e : m_e) if(mapping[e.from] == mapping[e.to] && mapping[e.to] >= 0) res[mapping[e.to]].addEdge(indexV[e.from], indexV[e.to]);
        return res;
    }
    CsrArray<int> getEdgeIndexArray(bool undirected) const {
        std::vector<std::pair<int, int>> src;
        src.reserve(numEdges() * (undirected ? 2 : 1));
        for(int i=0; i<numEdges(); i++){
            auto e = operator[](i);
            src.emplace_back(e.from, i);
            if(undirected) src.emplace_back(e.to, i);
        }
        return CsrArray<int>::Construct(numVertices(), src);
    }
    CsrArray<int> getEdgeIndexArray() const { return getEdgeIndexArray(isUndirected()); }
    CsrArray<int> getAdjacencyArray(bool undirected) const {
        std::vector<std::pair<int, int>> src;
        src.reserve(numEdges() * (undirected ? 2 : 1));
        for(auto e : m_e){
            src.emplace_back(e.from, e.to);
            if(undirected) src.emplace_back(e.to, e.from);
        }
        return CsrArray<int>::Construct(numVertices(), src);
    }
    CsrArray<int> getAdjacencyArray() const { return getAdjacencyArray(isUndirected()); }
private:
    int m_n;
    std::vector<Edge> m_e;
    bool m_isUndir;
};

} // namespace nachia


vector<pair<int,int>> ConstructionOfATree(
    int N,
    int M,
    vector<vector<int>> E
){
    //cout << endl;
    //rep(i,M){
    //    cout << E[i].size();
    //    for(auto v : E[i]) cout << " " << (v+1);
    //    cout << endl;
    //}
    //cout << endl;
    vector<int> matching(M); {
        vector<pair<int,int>> edges;
        rep(i,M) for(int e : E[i]) edges.push_back({ i, e });
        auto matchbuf = nachia::BipertiteMatching(M, N, edges);
        if(int(matchbuf.size()) != M) return {};
        for(int e : matchbuf) matching[edges[e].first] = edges[e].second;
    }
    //cout << "##" << endl;

    vector<int> matched(N);
    rep(i,M) matched[matching[i]] = 1;
    vector<int> roots;
    rep(i,N) if(matched[i] == 0) roots.push_back(i);

    //cout << "roots : ";
    //for(auto root : roots) cout << root << " ";
    //cout << endl;

    auto graph = nachia::Graph(N, false);
    rep(i,M){
        int v = matching[i];
        for(int e : E[i]) if(e != v) graph.addEdge(e, v);
    }
    vector<int> parent(N, -1);
    vector<int> bfs;
    int bfsi = 0;
   // cout << "##" << endl;


    for(int root : roots){
        bfs.push_back(root);
        parent[root] = -2;
        auto adj = graph.getAdjacencyArray();
        for( ; bfsi<int(bfs.size()); bfsi++){
            int v = bfs[bfsi];
            for(int w : adj[v]) if(parent[w] == -1){
                parent[w] = v;
                bfs.push_back(w);
            }
        }
    }
    if(int(bfs.size()) != N){ return {}; }
    vector<pair<int,int>> res(M);
    rep(i,M){
        res[i] = { matching[i], parent[matching[i]] };
    }
    return res;
}


namespace nachia {

struct DsuFast{
private:
    std::vector<int> w;
public:
    DsuFast(int n = 0) : w(n, -1) {}
    int leader(int u){
        if(w[u] < 0) return u;
        return w[u] = leader(w[u]);
    }
    int operator[](int u){ return leader(u); }
    int merge(int u, int v){
        u = leader(u);
        v = leader(v);
        if(u == v) return u;
        if(-w[u] < -w[v]) std::swap(u, v);
        w[u] += w[v];
        w[v] = u;
        return u;
    }
    int size(int u){ return -w[leader(u)]; }
    bool same(int u, int v){ return leader(u) == leader(v); }
};

} // namespace nachia

void testcase(){
    int H, W; cin >> H >> W;
    vector<string> A(H*2+1); rep(y,H*2+1) cin >> A[y];
    int cnt[2] = {};
    rep(y,H) rep(x,W) if(A[y*2+1][x*2+1] == '.') cnt[(y+x)%2]++;
    if(cnt[0] == cnt[1]){ cout << "No\n"; return; }
    int way = cnt[0] < cnt[1] ? 0 : 1;
    vector<vector<int>> idx(H, vector<int>(W, -1)); {
        int idxi = 0;
        rep(y,H) rep(x,W) if(A[y*2+1][x*2+1] == '.' && (x+y)%2 == way) idx[y][x] = idxi++;
        rep(y,H) rep(x,W) if(A[y*2+1][x*2+1] == '.' && (x+y)%2 != way) idx[y][x] = idxi++;
    }
    //rep(y,H){
    //    rep(x,W) cout << idx[y][x] << " ";
    //    cout << endl;
    //}
    vector<vector<int>> edges(cnt[way]);
    auto addEdge = [&](int u, int v){
        if(u == -1 || v == -1) return;
        if(u < cnt[way]) edges[u].push_back(v - cnt[way]);
        else edges[v].push_back(u - cnt[way]);
    };
    rep(y,H) rep(x,W-1) if(A[y*2+1][x*2+2] == '.') addEdge(idx[y][x], idx[y][x+1]);
    rep(y,H-1) rep(x,W) if(A[y*2+2][x*2+1] == '.') addEdge(idx[y][x], idx[y+1][x]);
    auto tre = ConstructionOfATree(cnt[way^1], cnt[way], edges);
    //for(auto [u,v] : tre){
    //    cout << u << " " << v << endl;
    //}
    if(tre.empty() && cnt[way] != 0){ cout << "No\n"; return; }

   // cout << "##" << endl;

    auto dsu = nachia::DsuFast(cnt[0] + cnt[1]);
    vector<pair<int,int>> Q;
    auto checkEdge = [&](int u, int v){
        if(u > v) swap(u,v);
        if(dsu.same(u,v)) return;
        dsu.merge(u,v);
        Q.push_back({u,v});
    };

    //cout << "##" << endl;

    rep(i,cnt[way]){
        checkEdge(i, tre[i].first + cnt[way]);
        checkEdge(i, tre[i].second + cnt[way]);
    }
    rep(y,H) rep(x,W-1) if(A[y*2+1][x*2+2] == '.') checkEdge(idx[y][x], idx[y][x+1]);
    rep(y,H-1) rep(x,W) if(A[y*2+2][x*2+1] == '.') checkEdge(idx[y][x], idx[y+1][x]);

    //cout << "##" << endl;

    if(Q.size() != cnt[0] + cnt[1] - 1){
        cout << "No\n";
        return;
    }

    sort(Q.begin(), Q.end());
    auto hasEdge = [&](int u, int v){
        if(u > v) swap(u,v);
        return binary_search(Q.begin(), Q.end(), make_pair(u,v));
    };

    rep(y,H) rep(x,W-1) if(!hasEdge(idx[y][x], idx[y][x+1])) A[y*2+1][x*2+2] = '#';
    rep(y,H-1) rep(x,W) if(!hasEdge(idx[y][x], idx[y+1][x])) A[y*2+2][x*2+1] = '#';
    cout << "Yes\n";
    rep(y,H*2+1) cout << A[y] << "\n";
}

int main(){
    ios::sync_with_stdio(false); cin.tie(nullptr);
    testcase();
    return 0;
}
accuracy: 1
time_ms: 930
memory_kb: 21896
final_rank: 2

code_snippet: // copied https://codeforces.com/contest/1284/submission/203129481

// LUOGU_RID: 108774415
#include <bits/stdc++.h>
using namespace std;
int k, n, m, s, t, tot = 1, flow, maxflow, allflow;
int dep[1000001], vis[1000001], fa[1000001], head[1000001], now[1000001], ver[1000001], edge[1000001], nex[1000001];
int dx[5] = {0, 0, 1, -1}, dy[5] = {1, -1, 0, 0};
char ch[888][888];

vector<int> G[1000001];
queue<int> q;
#define id(i, j) ((i - 1) * m + j)
int find(int x) {
	if (fa[x] != x)
		fa[x] = find(fa[x]);
	return fa[x];
}
vector<pair<int, int>> cand;

void merge(int x, int y) {
	int fx = find(x), fy = find(y);
	if (fx == fy)
		return;
	fa[fx] = fy;
	cand.push_back({(x - 1) / m + (y - 1) / m + 1, (x - 1) % m + (y - 1) % m + 1});
}
void add(int u, int v, int w) {
	ver[++tot] = v, edge[tot] = w, nex[tot] = head[u], head[u] = tot;
	ver[++tot] = u, edge[tot] = 0, nex[tot] = head[v], head[v] = tot;
}
bool bfs() {
	memset(dep, 0, sizeof(dep));
	while (q.size())
		q.pop();
	q.push(s);
	dep[s] = 1;
	while (q.size()) {
		int x = q.front();
		q.pop();
		for (int i = head[x]; i; i = nex[i]) {
			if (edge[i] && !dep[ver[i]]) {
				q.push(ver[i]);
				dep[ver[i]] = dep[x] + 1;
				if (ver[i] == t)
					return true;
			}
		}
	}
	return false;
}
int dinic(int x, int flow) {
	if (x == t)
		return flow;
	int rest = flow, k;
	for (int i = now[x]; i && rest; i = nex[i]) {
		now[x] = i;
		if (edge[i] && dep[ver[i]] == dep[x] + 1) {
			k = dinic(ver[i], min(edge[i], rest));
			if (!k)
				dep[ver[i]] = 0;
			rest -= k;
			edge[i] -= k;
			edge[i ^ 1] += k;
		}
	}
	return flow - rest;
}

bool edges(int x1, int y1, int x2, int y2) {
	int d = x1 + x2 - 1;
	int e = y1 + y2 - 1;
	if (ch[d][e] == '.')
		return true;
	return false;
}

void solve(int parity) {
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (ch[2 * i - 1][2 * j - 1] == '.') {
				if ((i + j) % 2 == parity) {
					allflow++;
					add(s, id(i, j), 1);
					for (int d = 0; d <= 3; d++) {
						int x = i + dx[d], y = j + dy[d];
						if (x < 1 || y < 1 || x > n || y > m || ch[2 * x - 1][2 * y - 1] != '.' || !edges(i, j, x, y))
							continue;
						add(id(i, j), id(x, y), 1);
					}
				} else
					add(id(i, j), t, 1);
			}
			fa[id(i, j)] = id(i, j);
			G[id(i, j)].clear();
		}
	}
	while (bfs()) {
		for (int i = s; i <= t; i++)
			now[i] = head[i];
		while (flow = dinic(s, 1e9))
			maxflow += flow;
	}
	if (maxflow != allflow) {
		return;
	}
	while (q.size())
		q.pop();
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (ch[2 * i - 1][2 * j - 1] == '.') {
				if ((i + j) % 2 != parity) {
					for (int d = 0; d <= 3; d++) {
						int x = i + dx[d], y = j + dy[d];
						if (x < 1 || y < 1 || x > n || y > m || ch[2 * x - 1][2 * y - 1] == '#' || !edges(i, j, x, y))
							continue;
						G[id(i, j)].push_back(id(x, y));
					}
				} else
					for (int d = head[id(i, j)]; d; d = nex[d])
						if (ver[d] != s && !edge[d])
							G[id(i, j)].push_back(ver[d]);
			}
		}
	}
	for (int i = head[t]; i; i = nex[i])
		if (!edge[i])
			q.push(ver[i]);
	while (q.size()) {
		int x = q.front();
		q.pop();
		if (vis[x])
			continue;
		vis[x] = 1;
		for (int i = 0; i < G[x].size(); i++) {
			merge(G[x][i], x);
			q.push(G[x][i]);
		}
	}
	int fuck = -1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (ch[2 * i - 1][2 * j - 1] == '.') {
				fuck = id(i, j);
			}
		}
	}

	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (ch[2 * i - 1][2 * j - 1] == '.' && find(fuck) != find(id(i, j))) {
				return;
			}
		}
	}
	for (int i = 1; i <= 2 * n - 1; i++) {
		for (int j = 1; j <= 2 * m - 1; j++) {
			if (i % 2 != j % 2)
				ch[i][j] = '#';
		}
	}
	for (auto &[x, y] : cand)
		ch[x][y] = '.';
	printf("Yes\n");
	for (int i = 0; i <= 2 * n; i++) {
		printf("%s\n", ch[i]);
	}
	exit(0);
}

int main() {
	scanf("%d%d", &n, &m);
	t = n * m + 1;
	for (int i = 0; i <= 2 * n; i++)
		scanf("%s", ch[i]);
	for (int it = 0; it < 2; it++) {
		maxflow = allflow = 0;
		tot = 1;

		memset(head, 0, sizeof(head));
		memset(vis, 0, sizeof(vis));
		solve(it);
		cand.clear();
	}
	printf("No\n");
}
accuracy: 1
time_ms: 1860
memory_kb: 61540
final_rank: 4