Source Code
import java.io.*;
import java.util.*;

/**
 * Made by egor https://github.com/chermehdi/egor.
 *
 * @author Azuz 
 *
 */
public class Main {

  private static final int BOT = 0, LEFT = 1, TOP = 2, RIGHT = 3;
  private static final int VER = 0, HOR = 1;

  int n, m, ans;
  int size = 0;
  char[][] arr;
  boolean[][] vis;
  boolean[][][] avis;

  void solve(InputReader in, PrintWriter out) {
    n = in.nextInt();
    m = in.nextInt();
    arr = new char[n][];

    for (int i = 0; i < n; ++i) {
      arr[i] = in.next().toCharArray();
    }

    UnionFind uf = new UnionFind(n, m);
    // Add UF connectivity without considering mirrors
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < m; ++j) if (arr[i][j] == '.') {
        // Vertical
        
        if (i - 1 >= 0 && arr[i - 1][j] == '.') {
          uf.union(i, j, VER, i - 1, j, VER);
        }
        // Horizontal
        if (j - 1 >= 0 && arr[i][j - 1] == '.') {
          uf.union(i, j, HOR, i, j - 1, HOR);
        }
      }
    }

    // Add UF using only mirrors
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < m; ++j) if (arr[i][j] == '/' || arr[i][j] == '\\'){
        if (arr[i][j] == '/') { // / mirror
          if (i + 1 < n && j + 1 < m) {
            int x1 = i + 1, y1 = j, dir1 = BOT;
            int x2 = i, y2 = j + 1, dir2 = RIGHT;
            while (x1 >= 0 && y1 >= 0 && x1 < n && y1 < m && arr[x1][y1] != '.') {
              if (x1 == i && y1 == j) break;
              if (arr[x1][y1] == '#') break;
              if (arr[x1][y1] == '/') {
                if (dir1 == BOT)   {y1--; dir1=LEFT;} 
                if (dir1 == TOP)   {y1++; dir1=RIGHT;} 
                if (dir1 == LEFT)  {x1++; dir1=BOT;}
                if (dir1 == RIGHT) {x1--; dir1=TOP;} 
              } else if (arr[x1][y1] == '\\') {
                if (dir1 == BOT)   {++y1; dir1=RIGHT;} 
                if (dir1 == TOP)   {--y1; dir1=LEFT;} 
                if (dir1 == RIGHT) {++x1; dir1=BOT;}
                if (dir1 == LEFT)  {--x1; dir1=TOP;} 
              }
            }

            while (x2 >= 0 && y2 >= 0 && x2 < n && y2 < m && arr[x2][y2] != '.') {
              if (x2 == i && j == y2) break;
              if (arr[x2][y2] == '#') break;
              if (arr[x2][y2] == '/') {
                if (dir2 == BOT)   {y2--; dir2=LEFT;} 
                if (dir2 == TOP)   {y2++; dir2=RIGHT;} 
                if (dir2 == LEFT)  {x2++; dir2=BOT;}
                if (dir2 == RIGHT) {x2--; dir2=TOP;} 
              } else if (arr[x2][y2] == '\\') {
                if (dir2 == BOT)   {++y2; dir2=RIGHT;} 
                if (dir2 == TOP)   {--y2; dir2=LEFT;} 
                if (dir2 == RIGHT) {++x2; dir2=BOT;}
                if (dir2 == LEFT)  {--x2; dir2=TOP;} 
              }
            }

            int d1 = dir1 == LEFT || dir1 == RIGHT ? HOR : VER;
            int d2 = dir2 == LEFT || dir2 == RIGHT ? HOR : VER;

            if (x1 >= 0 && x1 < n && y1 < m && y1 >= 0 && x2 >= 0 && x2 < n && y2 >= 0 && y2 < m
                && arr[x1][y1] == '.' && arr[x2][y2] == '.') {

              uf.union(x1, y1, d1, x2, y2, d2);
            }
          } 

          if (i - 1 < n && j - 1 < m) {
            int x1 = i - 1, y1 = j, dir1 = TOP;
            int x2 = i, y2 = j - 1, dir2 = LEFT;
            while (x1 >= 0 && y1 >= 0 && x1 < n && y1 < m && arr[x1][y1] != '.') {
              if (x1 == i && y1 == j) break;
              if (arr[x1][y1] == '#') break;
              if (arr[x1][y1] == '/') {
                if (dir1 == BOT)   {y1--; dir1=LEFT;} 
                if (dir1 == TOP)   {y1++; dir1=RIGHT;} 
                if (dir1 == LEFT)  {x1++; dir1=BOT;}
                if (dir1 == RIGHT) {x1--; dir1=TOP;} 
              } else if (arr[x1][y1] == '\\') {
                if (dir1 == BOT)   {++y1; dir1=RIGHT;} 
                if (dir1 == TOP)   {--y1; dir1=LEFT;} 
                if (dir1 == RIGHT) {++x1; dir1=BOT;}
                if (dir1 == LEFT)  {--x1; dir1=TOP;} 
              }
            }

            while (x2 >= 0 && y2 >= 0 && x2 < n && y2 < m && arr[x2][y2] != '.') {
              if (x2 == i && j == y2) break;
              if (arr[x2][y2] == '#') break;
              if (arr[x2][y2] == '/') {
                if (dir2 == BOT)   {y2--; dir2=LEFT;} 
                if (dir2 == TOP)   {y2++; dir2=RIGHT;} 
                if (dir2 == LEFT)  {x2++; dir2=BOT;}
                if (dir2 == RIGHT) {x2--; dir2=TOP;} 
              } else if (arr[x2][y2] == '\\') {
                if (dir2 == BOT)   {++y2; dir2=RIGHT;} 
                if (dir2 == TOP)   {--y2; dir2=LEFT;} 
                if (dir2 == RIGHT) {++x2; dir2=BOT;}
                if (dir2 == LEFT)  {--x2; dir2=TOP;} 
              }
            }

            int d1 = dir1 == LEFT || dir1 == RIGHT ? HOR : VER;
            int d2 = dir2 == LEFT || dir2 == RIGHT ? HOR : VER;
            if (i == 15 && j == 4)
              System.err.println(x1 + " " + y1 + "..." + x2 + " " + y2);

            if (x1 >= 0 && x1 < n && y1 < m && y1 >= 0 && x2 >= 0 && x2 < n && y2 >= 0 && y2 < m
                && arr[x1][y1] == '.' && arr[x2][y2] == '.') {
              uf.union(x1, y1, d1, x2, y2, d2);
            }
          }

        } else { // \ Mirror

          if (i - 1 < n && j + 1 < m) {
            int x1 = i - 1, y1 = j, dir1 = TOP;
            int x2 = i, y2 = j + 1, dir2 = RIGHT;
            while (x1 >= 0 && y1 >= 0 && x1 < n && y1 < m && arr[x1][y1] != '.') {
              if (x1 == i && y1 == j) break;
              if (arr[x1][y1] == '#') break;
              if (arr[x1][y1] == '/') {
                if (dir1 == BOT)   {y1--; dir1=LEFT;} 
                if (dir1 == TOP)   {y1++; dir1=RIGHT;} 
                if (dir1 == LEFT)  {x1++; dir1=BOT;}
                if (dir1 == RIGHT) {x1--; dir1=TOP;} 
              } else if (arr[x1][y1] == '\\') {
                if (dir1 == BOT)   {++y1; dir1=RIGHT;} 
                if (dir1 == TOP)   {--y1; dir1=LEFT;} 
                if (dir1 == RIGHT) {++x1; dir1=BOT;}
                if (dir1 == LEFT)  {--x1; dir1=TOP;} 
              }
            }

            while (x2 >= 0 && y2 >= 0 && x2 < n && y2 < m && arr[x2][y2] != '.') {
              if (x2 == i && j == y2) break;
              if (arr[x2][y2] == '#') break;
              if (arr[x2][y2] == '/') {
                if (dir2 == BOT)   {y2--; dir2=LEFT;} 
                if (dir2 == TOP)   {y2++; dir2=RIGHT;} 
                if (dir2 == LEFT)  {x2++; dir2=BOT;}
                if (dir2 == RIGHT) {x2--; dir2=TOP;} 
              } else if (arr[x2][y2] == '\\') {
                if (dir2 == BOT)   {++y2; dir2=RIGHT;} 
                if (dir2 == TOP)   {--y2; dir2=LEFT;} 
                if (dir2 == RIGHT) {++x2; dir2=BOT;}
                if (dir2 == LEFT)  {--x2; dir2=TOP;} 
              }
            }

            int d1 = dir1 == LEFT || dir1 == RIGHT ? HOR : VER;
            int d2 = dir2 == LEFT || dir2 == RIGHT ? HOR : VER;

            if (x1 >= 0 && x1 < n && y1 < m && y1 >= 0 && x2 >= 0 && x2 < n && y2 >= 0 && y2 < m
                && arr[x1][y1] == '.' && arr[x2][y2] == '.') {
              uf.union(x1, y1, d1, x2, y2, d2);
            }
          } 

          if (i + 1 < n && j - 1 < m) {
            int x1 = i + 1, y1 = j, dir1 = BOT;
            int x2 = i, y2 = j - 1, dir2 = LEFT;
            while (x1 >= 0 && y1 >= 0 && x1 < n && y1 < m && arr[x1][y1] != '.') {
              if (x1 == i && y1 == j) break;
              if (arr[x1][y1] == '#') break;
              if (arr[x1][y1] == '/') {
                if (dir1 == BOT)   {y1--; dir1=LEFT;} 
                if (dir1 == TOP)   {y1++; dir1=RIGHT;} 
                if (dir1 == LEFT)  {x1++; dir1=BOT;}
                if (dir1 == RIGHT) {x1--; dir1=TOP;} 
              } else if (arr[x1][y1] == '\\') {
                if (dir1 == BOT)   {++y1; dir1=RIGHT;} 
                if (dir1 == TOP)   {--y1; dir1=LEFT;} 
                if (dir1 == RIGHT) {++x1; dir1=BOT;}
                if (dir1 == LEFT)  {--x1; dir1=TOP;} 
              }
            }

            while (x2 >= 0 && y2 >= 0 && x2 < n && y2 < m && arr[x2][y2] != '.') {
              if (x2 == i && j == y2) break;
              if (arr[x2][y2] == '#') break;
              if (arr[x2][y2] == '/') {
                if (dir2 == BOT)   {y2--; dir2=LEFT;} 
                if (dir2 == TOP)   {y2++; dir2=RIGHT;} 
                if (dir2 == LEFT)  {x2++; dir2=BOT;}
                if (dir2 == RIGHT) {x2--; dir2=TOP;} 
              } else if (arr[x2][y2] == '\\') {
                if (dir2 == BOT)   {++y2; dir2=RIGHT;} 
                if (dir2 == TOP)   {--y2; dir2=LEFT;} 
                if (dir2 == RIGHT) {++x2; dir2=BOT;}
                if (dir2 == LEFT)  {--x2; dir2=TOP;} 
              }
            }

            int d1 = dir1 == LEFT || dir1 == RIGHT ? HOR : VER;
            int d2 = dir2 == LEFT || dir2 == RIGHT ? HOR : VER;

            if (x1 >= 0 && x1 < n && y1 < m && y1 >= 0 && x2 >= 0 && x2 < n && y2 >= 0 && y2 < m
                && arr[x1][y1] == '.' && arr[x2][y2] == '.') {
              uf.union(x1, y1, d1, x2, y2, d2);
            }
          }
          
        }
      }
    }

    
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < m; ++j) {
        int a = uf.find(i, j, VER);
        int b = uf.find(i, j, HOR);
        if (a == b) { // Exception
           uf.reduce(a, b);
        }
      }
    }/* 
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < m; ++j) {
        System.err.print(uf.size(i, j, VER) + "/" + uf.size(i, j, HOR) + " ");
      } System.err.println();
    }*/

    int max = -1;
    int maxi = -1;
    int maxj = -1;
    PriorityQueue<Tuple> q = new PriorityQueue<>();
    
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < m; ++j) {

        int x = 0;
        if (uf.find(i, j, 0) == uf.find(i, j, 1)) {
          x = uf.size(i, j, 0);
        } else {
          x = uf.size(i, j) - 1;
        }

        q.offer(new Tuple(i, j, x));
        if (q.size() > 10) {
          q.poll();
        }
      }
    }

    // System.err.println(maxi + " " + maxj + " " + max);
    
    if (max < 0) {
      out.println(0);
      return ;
    }

    // Simulate 
        ans = 0;
    while (!q.isEmpty()) {
      vis = new boolean[n][m];
      avis = new boolean[n][m][4];
      size = 0;
      Tuple t = q.poll();
      for (int dir = 0; dir < 4; ++dir) {
        dfs(t.i, t.j, dir);
      }
      ans = Math.max(ans, size);
    }
    
    out.println(ans );
  }

  private static class Tuple  implements Comparable<Tuple> {
    int i, j, val;

    public Tuple(int i, int j, int val) {
      this.i = i;
      this.j = j;
      this.val = val;
    }

    @Override
    public int compareTo(Tuple t) {
      return Integer.compare(t.val, this.val);
    }
  }

  private void dfs(int i, int j, int dir) {
    if (i < 0 || j < 0) return ;
    if (i >= n || j >= m) return ;
    if (arr[i][j] == '#') return ;
    if (avis[i][j][dir]) return ;
    if (!vis[i][j] && arr[i][j] == '.') ++size;
    avis[i][j][dir] = true;
    vis[i][j] = true;

    // System.err.println(i + " " + j + " > " + dir);


    if (arr[i][j] == '.') {
      if (dir == BOT) dfs(i + 1, j, dir);
      if (dir == TOP) dfs(i - 1, j, dir);
      if (dir == RIGHT) dfs(i, j + 1, dir);
      if (dir == LEFT) dfs(i, j - 1, dir);
    } else if (arr[i][j] == '/') {

      if (dir == BOT) dfs(i, j - 1, LEFT);
      if (dir == TOP) dfs(i, j + 1, RIGHT);
      if (dir == LEFT) dfs(i + 1, j, BOT);
      if (dir == RIGHT) dfs(i - 1, j, TOP);

    } else  { // \
      
      if (dir == BOT) dfs(i, j + 1, RIGHT);
      if (dir == TOP) dfs(i, j - 1, LEFT);
      if (dir == RIGHT) dfs(i + 1, j, BOT);
      if (dir == LEFT) dfs(i - 1, j, TOP);
      
    }
  }

  public static void main(String[] args) {
    InputReader in = new InputReader(System.in);
    try (PrintWriter out = new PrintWriter(System.out)) {
      new Main().solve(in, out);
    }
  }
}

class UnionFind {
  int[] p, size;
  int n, m;
  int max_size;
  public UnionFind(int n, int m) {
    this.n = n;
    this.m = m;
    this.max_size = this.encode(n, m, 1) + 1;
    size = new int[max_size];
    p = new int[max_size];
    for (int dir = 0; dir < 2; ++dir) {
      for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
          int code = encode(i, j, dir);
          p[code] = code;
          size[code] = 1;
        }
      }
    }
  }

  public int size(int i, int j, int dir) {
    int code = encode(i, j, dir);
    return size[find(code)];
  }

  public int size(int i, int j) {
    return size(i, j, 0) + size(i, j, 1);
  }

  private void union(int u, int v) {
    int x = find(u);
    int y = find(v);
    if (x == y) return ;
    if (size[x] > size[y]) {
      size[x] += size[y];
      p[y] = x;
    } else {
      size[y] += size[x];
      p[x] = p[y];
    }
  }

  public void union(int i, int j, int dirij, int x, int y, int dirxy) {
    int codeij = encode(i, j, dirij);
    int codexy = encode(x, y, dirxy);
    union(codeij, codexy);
  }

  public void reduce(int c1, int c2) {
    if (size[c1] > c2) {
      size[c1]--;
    } else {
      size[c2]--;
    }
  }

  public int find(int i, int j, int dir) {
    int code = encode(i, j, dir);
    return find(code);
  }

  private int find(int code) {
    if (p[code] == code) return code;
    return p[code] = find(p[code]);
  }

  private int encode(int i, int j, int dir) {
    int ret = (dir * this.n * this.m) + (i * this.m) + j;
    return ret; 
  }
}

class InputReader  {

  private InputStream stream;
  private static final int DEFAULT_BUFFER_SIZE = 1 << 16;
  private static final int EOF = -1;
  private byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
  private int curChar;
  private int numChars;

  public InputReader(InputStream stream) {
    this.stream = stream;
  }

  public int[] readIntArray(int tokens) {
    int[] ret = new int[tokens];
    for (int i = 0; i < tokens; i++) {
      ret[i] = nextInt();
    }
    return ret;
  }

  public int read() {
    if (this.numChars == EOF) {
      throw new UnknownError();
    } else {
      if (this.curChar >= this.numChars) {
        this.curChar = 0;

        try {
          this.numChars = this.stream.read(this.buf);
        } catch (IOException ex) {
          throw new InputMismatchException();
        }

        if (this.numChars <= 0) {
          return EOF;
        }
      }

      return this.buf[this.curChar++];
    }
  }

  public int nextInt() {
    int c;
    for (c = this.read(); isSpaceChar(c); c = this.read()) {
    }

    byte sgn = 1;
    if (c == 45) {
      sgn = -1;
      c = this.read();
    }

    int res = 0;

    while (c >= 48 && c <= 57) {
      res *= 10;
      res += c - 48;
      c = this.read();
      if (isSpaceChar(c)) {
        return res * sgn;
      }
    }

    throw new InputMismatchException();
  }

  public long nextLong() {
    int c;
    for (c = this.read(); isSpaceChar(c); c = this.read()) {
    }

    byte sgn = 1;
    if (c == 45) {
      sgn = -1;
      c = this.read();
    }

    long res = 0;

    while (c >= 48 && c <= 57) {
      res *= 10L;
      res += c - 48;
      c = this.read();
      if (isSpaceChar(c)) {
        return res * sgn;
      }
    }
    throw new InputMismatchException();
  }

  public double nextDouble() {
    double ret = 0, div = 1;
    int c = read();
    while (c <= ' ') {
      c = read();
    }
    boolean neg = (c == '-');
    if (neg) {
      c = read();
    }

    do {
      ret = ret * 10 + c - '0';
    }
    while ((c = read()) >= '0' && c <= '9');

    if (c == '.') {
      while ((c = read()) >= '0' && c <= '9') {
        ret += (c - '0') / (div *= 10);
      }
    }

    if (neg) {
      return -ret;
    }
    return ret;
  }

  public String next() {
    int c;
    while (isSpaceChar(c = this.read())) {
    }

    StringBuilder result = new StringBuilder();
    result.appendCodePoint(c);

    while (!isSpaceChar(c = this.read())) {
      result.appendCodePoint(c);
    }

    return result.toString();
  }

  public String nextLine() {
    int c;
    StringBuilder result = new StringBuilder();
    boolean read = false;
    while ((c = this.read()) != '\n') {
      if (c == -1) {
        return null;
      }
      result.appendCodePoint(c);
      read = true;
    }
    if (!read) {
      return null;
    }
    return result.toString();
  }

  public static boolean isSpaceChar(int c) {
    return c == 32 || c == 10 || c == 13 || c == 9 || c == EOF;
  }

  public int[] nextIntArray(int n) {
    int[] arr = new int[n];
    for (int i = 0; i < n; i++) {
      arr[i] = nextInt();
    }
    return arr;
  }

  public long[] nextLongArray(int n) {
    long[] arr = new long[n];
    for (int i = 0; i < n; i++) {
      arr[i] = nextLong();
    }
    return arr;
  }

  public int[][] nextIntMatrix(int n, int m) {
    int[][] arr = new int[n][m];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        arr[i][j] = nextInt();
      }
    }
    return arr;
  }

  public long[][] nextLongMatrix(int n, int m) {
    long[][] arr = new long[n][m];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        arr[i][j] = nextLong();
      }
    }
    return arr;
  }

  public char[] nextCharArray() {
    return next().toCharArray();
  }

  public double[] nextDoubleArray(int n) {
    double[] ret = new double[n];
    for (int i = 0; i < n; i++) {
      ret[i] = nextDouble();
    }
    return ret;
  }

  public int[]
  nextIntArrayOneBased(int n) {
    int[] ret = new int[n + 1];
    for (int i = 1; i <= n; i++) {
      ret[i] = nextInt();
    }
    return ret;
  }

  public char[][] nextCharMatrix(int n, int m) {
    char[][] res = new char[n][m];
    for (int i = 0; i < n; ++i) {
      res[i] = nextCharArray();
    }
    return res;
  }
}
Copy
Mirrors Azuz
Java 11
65 ms
13.0 MB
Wrong Answer