Problem:
Score : 400 points

Problem Statement

A maze is composed of a grid of H \times W squares - H vertical, W horizontal.

The square at the i-th row from the top and the j-th column from the left - (i,j) - is a wall if S_{ij} is # and a road if S_{ij} is ..

There is a magician in (C_h,C_w). He can do the following two kinds of moves:

Move A: Walk to a road square that is vertically or horizontally adjacent to the square he is currently in.

Move B: Use magic to warp himself to a road square in the 5\times 5 area centered at the square he is currently in.

In either case, he cannot go out of the maze.

At least how many times does he need to use the magic to reach (D_h, D_w)?

Constraints

1 \leq H,W \leq 10^3

1 \leq C_h,D_h \leq H

1 \leq C_w,D_w \leq W

S_{ij} is # or ..

S_{C_h C_w} and S_{D_h D_w} are ..

(C_h,C_w) \neq (D_h,D_w)

Input

Input is given from Standard Input in the following format:

H W
C_h C_w
D_h D_w
S_{11}\ldots S_{1W}
\vdots
S_{H1}\ldots S_{HW}

Output

Print the minimum number of times the magician needs to use the magic. If he cannot reach (D_h,D_w), print -1 instead.

Sample Input 1

4 4
1 1
4 4
..#.
..#.
.#..
.#..

Sample Output 1

1

For example, by walking to (2,2) and then using the magic to travel to (4,4), just one use of magic is enough.

Note that he cannot walk diagonally.

Sample Input 2

4 4
1 4
4 1
.##.
####
####
.##.

Sample Output 2

-1

He cannot move from there.

Sample Input 3

4 4
2 2
3 3
....
....
....
....

Sample Output 3

0

No use of magic is needed.

Sample Input 4

4 5
1 2
2 5
#.###
####.
#..##
#..##

Sample Output 4

2

Solution in C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using static Assistant.Input;
using static Assistant.Debug;
using System.Linq;
using Assistant;

namespace ABC176D
{
    class Program
    {
        static void Main(string[] args)
        {
            var H = RInt;
            var W = RInt;
            var Ch = RInt - 1;
            var Cw = RInt - 1;
            var Dh = RInt - 1;
            var Dw = RInt - 1;

            char[,] S = new char[H, W];
            for (int i = 0; i < H; i++)
            {
                var input = Console.ReadLine();
                for (int j = 0; j < W; j++)
                {
                    S[i, j] = input[j];
                }
            }

            int ans = 0;
            int[] dx = new int[] { -1, 0, 1, 0 };
            int[] dy = new int[] { 0, 1, 0, -1 };
            int[,] map = new int[H, W];
            for (int i = 0; i < H; i++)
            {
                for (int j = 0; j < W; j++)
                {
                    if (map[i, j] > 0) continue;
                    if (S[i, j] != '.') continue;
                    ans++;
                    map[i, j] = ans;

                    //接続部をすべて塗る
                    Queue<int> x = new Queue<int>();
                    Queue<int> y = new Queue<int>();
                    x.Enqueue(i);
                    y.Enqueue(j);

                    while (x.Count > 0)
                    {
                        int px = x.Dequeue();
                        int py = y.Dequeue();
                        for (int k = 0; k < 4; k++)
                        {
                            int tx = px + dx[k];
                            int ty = py + dy[k];
                            if (tx < 0 || H <= tx || ty < 0 || W <= ty) continue;
                            if (S[tx, ty] != '.') continue;
                            if (map[tx, ty] > 0) continue;

                            x.Enqueue(tx);
                            y.Enqueue(ty);
                            map[tx, ty] = ans;
                        }
                    }
                }
            }

            int from = map[Ch, Cw];
            int to = map[Dh, Dw];

            Dijkstra dijkstra = new Dijkstra(H * W);
            for (int i = 0; i < H; i++)
            {
                for (int j = 0; j < W; j++)
                {
                    if (map[i, j] == 0) continue;
                    int f = i * W + j;
                    for (int k = 0; k < 5; k++)
                    {
                        for (int l = 0; l < 5; l++)
                        {
                            int tx = i + k - 2;
                            int ty = j + l - 2;
                            if (tx < 0 || H <= tx || ty < 0 || W <= ty) continue;
                            if (S[tx, ty] != '.') continue;
                            if (map[i, j] == map[tx, ty]) continue;
                            int t = tx * W + ty;
                            dijkstra.Add(map[i, j], map[tx, ty], 1);
                        }
                    }
                }
            }

            var dist = dijkstra.Start(from);
            var a = dist[to];
            if (a == long.MaxValue / 2) a = -1;
            if (from == to) a = 0;

            Console.WriteLine(a);
        }


    }

    public class PriorityQueue<T> where T : IComparable<T>
    {
        private IComparer<T> _comparer = null;
        private int _type = 0;

        private T[] _heap;
        private int _sz = 0;

        private int _count = 0;

        /// <summary>
        /// Priority Queue with custom comparer
        /// </summary>
        public PriorityQueue(IComparer<T> comparer, int capacity = 128)
        {
            _heap = new T[capacity];
            _comparer = comparer;
        }

        /// <summary>
        /// Priority queue
        /// </summary>
        /// <param name="type">0: asc, 1:desc</param>
        public PriorityQueue(int type = 0)
        {
            _heap = new T[128];
            _type = type;
        }

        private int Compare(T x, T y)
        {
            if (_comparer != null) return _comparer.Compare(x, y);
            return _type == 0 ? x.CompareTo(y) : y.CompareTo(x);
        }

        public void Push(T x)
        {
            _count++;
            if (_count > _heap.Length)
            {
                var newheap = new T[_heap.Length * 2];
                for (int n = 0; n < _heap.Length; n++) newheap[n] = _heap[n];
                _heap = newheap;
            }

            //node number
            var i = _sz++;

            while (i > 0)
            {
                //parent node number
                var p = (i - 1) / 2;

                if (Compare(_heap[p], x) <= 0) break;

                _heap[i] = _heap[p];
                i = p;
            }

            _heap[i] = x;
        }

        public T Pop()
        {
            _count--;

            T ret = _heap[0];
            T x = _heap[--_sz];

            int i = 0;
            while (i * 2 + 1 < _sz)
            {
                //children
                int a = i * 2 + 1;
                int b = i * 2 + 2;

                if (b < _sz && Compare(_heap[b], _heap[a]) < 0) a = b;

                if (Compare(_heap[a], x) >= 0) break;

                _heap[i] = _heap[a];
                i = a;
            }

            _heap[i] = x;

            return ret;
        }

        public int Count()
        {
            return _count;
        }

        public T Peek()
        {
            return _heap[0];
        }

        public bool Contains(T x)
        {
            for (int i = 0; i < _sz; i++) if (x.Equals(_heap[i])) return true;
            return false;
        }

        public void Clear()
        {
            while (this.Count() > 0) this.Pop();
        }

        public IEnumerator<T> GetEnumerator()
        {
            var ret = new List<T>();

            while (this.Count() > 0)
            {
                ret.Add(this.Pop());
            }

            foreach (var r in ret)
            {
                this.Push(r);
                yield return r;
            }
        }

        public T[] ToArray()
        {
            T[] array = new T[_sz];
            int i = 0;

            foreach (var r in this)
            {
                array[i++] = r;
            }

            return array;
        }
    }

    class Dijkstra
    {
        public long INF = long.MaxValue / 2;
        public int N { get; }               // 頂点の数
        private List<Edge>[] _graph;        // グラフの辺のデータ

        public Dijkstra(int n)
        {
            N = n;
            _graph = new List<Edge>[n];
            for (int i = 0; i < n; i++) _graph[i] = new List<Edge>();
        }

        public void Add(int a, int b, long cost = 1)
                => _graph[a].Add(new Edge(b, cost));

        public long[] Start(int start)
        {
            // コストをスタート頂点以外を無限大に
            var cost = new long[N];
            for (int i = 0; i < N; i++) cost[i] = INF;
            cost[start] = 0;

            // 未確定の頂点を格納する優先度付きキュー(コストが大きいほど優先度が高い)
            var q = new PriorityQueue<Vertex>(Comparer<Vertex>.Create((a, b) => -b.CompareTo(a)), N * 10);
            q.Push(new Vertex(start, 0));

            while (q.Count() > 0)
            {
                var v = q.Pop();

                // 記録されているコストと異なる(コストがより大きい)場合は無視
                if (v.cost != cost[v.index]) continue;

                foreach (var e in _graph[v.index])
                {
                    // 既に記録されているコストより小さければコストを更新
                    if (cost[e.to] > v.cost + e.cost)
                    {
                        cost[e.to] = v.cost + e.cost;
                        q.Push(new Vertex(e.to, cost[e.to]));
                    }
                }
            }

            // 確定したコストを返す
            return cost;
        }

        public struct Edge
        {
            public int to;                      // 接続先の頂点
            public long cost;                   // 辺のコスト

            public Edge(int to, long cost)
            {
                this.to = to;
                this.cost = cost;
            }
        }

        public struct Vertex : IComparable<Vertex>
        {
            public int index;                   // 頂点の番号
            public long cost;                   // 記録したコスト

            public Vertex(int index, long cost)
            {
                this.index = index;
                this.cost = cost;
            }

            public int CompareTo(Vertex other)
                => cost.CompareTo(other.cost);
        }
    }
}

namespace Assistant
{
    static class Input
    {
        static List<string> line = new List<string>();
        static int index = 0;
        static String RNext()
        {
            if (line.Count <= index) line.AddRange(Console.ReadLine().Split());
            return line[index++];
        }
        public static int RInt => int.Parse(RNext());
        public static long RLong => long.Parse(RNext());
        public static int[] RInts => Console.ReadLine().Split().Select(int.Parse).ToArray();
        public static long[] RLongs => Console.ReadLine().Split().Select(long.Parse).ToArray();
        public static string RString => RNext();
        //以下未テスト
        public static int[] RIntsC(int c) => Enumerable.Repeat(0, c).Select(x => int.Parse(RNext())).ToArray();
        public static long[] RLongsC(int c) => Enumerable.Repeat(0, c).Select(x => long.Parse(RNext())).ToArray();
        public static char[][] RMap(int h) => Enumerable.Repeat(0, h).Select(x => Console.ReadLine().ToCharArray()).ToArray();
    }

    public struct Mlong
    {
        long _v;
        const long mod = 1000000007;
        public Mlong(long n = 0) : this() { _v = n >= mod ? n % mod : n; }

        public static implicit operator Mlong(long _x) => new Mlong(_x);
        public static implicit operator long(Mlong _x) => _x._v;
        public static Mlong operator +(Mlong m1, Mlong m2) { long m = m1._v + m2._v; return m >= mod ? m - mod : m; }
        public static Mlong operator -(Mlong m1, Mlong m2) { long m = m1._v - m2._v; return m >= 0 ? m : m + mod; }
        public static Mlong operator *(Mlong m1, Mlong m2) => m1._v * m2._v % mod;
        public static Mlong operator /(Mlong m1, Mlong m2) => m1._v * ModPow(m2._v, mod - 2) % mod;

        public static long ModPow(long a, long n)
        {
            if (n == 0) return 1;
            else if (n % 2 == 1) return a * ModPow(a, n - 1) % mod;
            else return ModPow(a * a % mod, n / 2);
        }

        static Mlong[] fac, finv, inv;
        public static void nCkInit(int max)
        {
            fac = new Mlong[max]; finv = new Mlong[max]; inv = new Mlong[max];
            fac[0] = fac[1] = 1;
            finv[0] = finv[1] = 1;
            inv[1] = 1;
            for (int i = 2; i < max; i++)
            {
                fac[i] = fac[i - 1] * i;
                inv[i] = mod - inv[mod % i] * (mod / i);
                finv[i] = finv[i - 1] * inv[i];
            }
        }

        public static Mlong nCk(int n, int k)
        {
            if (n < k) return 0;
            if (n < 0 || k < 0) return 0;
            return fac[n] * finv[k] * finv[n - k];
        }
    }

    static class Debug
    {
        static public void Draw2D<T>(T[,] map, int mode = 1)
        {
#if DEBUG
            int W = map.GetLength(0);
            int H = map.GetLength(1);

            string[,] map2 = new string[W + 1, H + 1];
            for (int i = 0; i < W + 1; i++)
            {
                for (int j = 0; j < H + 1; j++)
                {
                    if (i == 0 && j == 0) map2[i, j] = 0.ToString();
                    else if (i == 0) map2[i, j] = (j - 1).ToString();
                    else if (j == 0) map2[i, j] = (i - 1).ToString();
                    else map2[i, j] = map[i - 1, j - 1].ToString();
                }
            }

            for (int i = 0; i < W + 1; i++)
            {
                for (int j = 0; j < H + 1; j++)
                {
                    if (mode == 0) Console.Write(map2[i, j].Last());
                    if (mode == 1) Console.Write(map2[i, j] + " ");
                }
                Console.WriteLine();
            }
            Console.WriteLine();
#endif
        }

        public static void Draw1D<T>(T[] array, int mode = 0)
        {
#if DEBUG
            Console.WriteLine(string.Join(" ", array));
#endif
        }
    }
}