#include <bits/stdc++.h>
using namespace std;
inline void open(const char *s) {}
inline int rd() {
  static int x, f;
  x = 0;
  f = 1;
  char ch = getchar();
  for (; ch < '0' || ch > '9'; ch = getchar())
    if (ch == '-') f = -1;
  for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
  return f > 0 ? x : -x;
}
const int N = 1000010;
int R, C, n, rt = 0, Lr;
vector<int> a[N];
pair<int, int> b[N];
namespace LCT {
struct tree {
  int ch[2], fa, rev;
  tree() { ch[0] = ch[1] = fa = rev = 0; }
} tr[N];
int cnt = 0;
inline bool isrt(int x) {
  return tr[tr[x].fa].ch[0] != x && tr[tr[x].fa].ch[1] != x;
}
inline void pushdown(int x) {
  if (!tr[x].rev) return;
  swap(tr[x].ch[0], tr[x].ch[1]);
  if (tr[x].ch[0]) tr[tr[x].ch[0]].rev ^= 1;
  if (tr[x].ch[1]) tr[tr[x].ch[1]].rev ^= 1;
  tr[x].rev = 0;
}
inline void clr(int x) {
  static int st[N], tt;
  for (st[tt = 1] = x; !isrt(x); x = tr[x].fa) st[++tt] = tr[x].fa;
  while (tt) pushdown(st[tt--]);
}
inline void rotate(int x) {
  static int y, z, t1, t2;
  y = tr[x].fa;
  z = tr[y].fa;
  t1 = tr[y].ch[1] == x;
  t2 = t1 ^ 1;
  if (!isrt(y)) tr[z].ch[tr[z].ch[1] == y] = x;
  tr[x].fa = z;
  tr[y].fa = x;
  if (tr[x].ch[t2]) tr[tr[x].ch[t2]].fa = y;
  tr[y].ch[t1] = tr[x].ch[t2];
  tr[x].ch[t2] = y;
}
inline void splay(int x) {
  for (clr(x); !isrt(x); rotate(x)) {
    int y = tr[x].fa, z = tr[y].fa;
    if (isrt(y)) continue;
    if ((tr[y].ch[0] == x) ^ (tr[z].ch[0] == y))
      rotate(x);
    else
      rotate(y);
  }
}
inline void access(int x) {
  for (int s = 0; x; s = x, x = tr[x].fa) {
    splay(x);
    tr[x].ch[1] = s;
  }
}
inline void makert(int x) {
  access(x);
  splay(x);
  tr[x].rev ^= 1;
}
inline int findrt(int x) {
  access(x);
  splay(x);
  pushdown(x);
  while (tr[x].ch[0]) x = tr[x].ch[0], pushdown(x);
  return x;
}
inline void link(int x, int y) {
  makert(x);
  access(y);
  splay(y);
  tr[x].fa = y;
}
inline void cut(int x, int y) {
  makert(y);
  access(x);
  splay(x);
  tr[tr[x].ch[0]].fa = 0;
  tr[x].ch[0] = 0;
}
}  // namespace LCT
namespace Seg {
struct tree {
  int ls, rs, mx, cmx, tag;
  tree() { ls = rs = mx = cmx = tag = 0; }
} tr[N << 1];
int cnt = 0;
inline void pushup(int o) {
  tr[o].mx = max(tr[tr[o].ls].mx, tr[tr[o].rs].mx);
  tr[o].cmx = 0;
  if (tr[o].mx == tr[tr[o].ls].mx) tr[o].cmx += tr[tr[o].ls].cmx;
  if (tr[o].mx == tr[tr[o].rs].mx) tr[o].cmx += tr[tr[o].rs].cmx;
}
inline void pushdown(int o) {
  if (!tr[o].tag) return;
  static int ls, rs;
  ls = tr[o].ls, rs = tr[o].rs;
  tr[ls].mx += tr[o].tag;
  tr[ls].tag += tr[o].tag;
  tr[rs].mx += tr[o].tag;
  tr[rs].tag += tr[o].tag;
  tr[o].tag = 0;
}
void build(int &o, int l, int r) {
  o = ++cnt;
  if (l == r) return tr[o].mx = l, tr[o].cmx = 1, void();
  int mid = (l + r) >> 1;
  build(tr[o].ls, l, mid);
  build(tr[o].rs, mid + 1, r);
  pushup(o);
}
void modify(int o, int l, int r, int L, int R, int d) {
  if (l == L && r == R) return tr[o].mx += d, tr[o].tag += d, void();
  pushdown(o);
  int mid = (l + r) >> 1;
  if (L <= mid) modify(tr[o].ls, l, mid, L, min(mid, R), d);
  if (R > mid) modify(tr[o].rs, mid + 1, r, max(mid + 1, L), R, d);
  pushup(o);
}
pair<int, int> query(int o, int l, int r, int L, int R) {
  if (l == L && r == R) return pair<int, int>(tr[o].mx, tr[o].cmx);
  pushdown(o);
  int mid = (l + r) >> 1;
  pair<int, int> res = pair<int, int>(0, 0), tmp;
  if (L <= mid) res = query(tr[o].ls, l, mid, L, min(mid, R));
  if (R > mid) {
    tmp = query(tr[o].rs, mid + 1, r, max(mid + 1, L), R);
    if (res.first == tmp.first)
      res.second += tmp.second;
    else
      res = max(res, tmp);
  }
  return res;
}
}  // namespace Seg
inline bool check(int p) {
  static int d[5], tt, x, y;
  tt = 0;
  x = b[p].first, y = b[p].second;
  if (x > 1 && a[x - 1][y] >= Lr && a[x - 1][y] < p)
    d[++tt] = LCT::findrt(a[x - 1][y]);
  if (y > 1 && a[x][y - 1] >= Lr && a[x][y - 1] < p)
    d[++tt] = LCT::findrt(a[x][y - 1]);
  if (x < R && a[x + 1][y] >= Lr && a[x + 1][y] < p)
    d[++tt] = LCT::findrt(a[x + 1][y]);
  if (y < C && a[x][y + 1] >= Lr && a[x][y + 1] < p)
    d[++tt] = LCT::findrt(a[x][y + 1]);
  sort(d + 1, d + tt + 1);
  for (int i = 1; i <= tt - 1; i++)
    if (d[i] == d[i + 1]) return 0;
  return 1;
}
inline void del(int p) {
  static int x, y;
  x = b[p].first, y = b[p].second;
  if (x > 1 && a[x - 1][y] >= p) LCT::cut(a[x - 1][y], p);
  if (y > 1 && a[x][y - 1] >= p) LCT::cut(a[x][y - 1], p);
  if (x < R && a[x + 1][y] >= p) LCT::cut(a[x + 1][y], p);
  if (y < C && a[x][y + 1] >= p) LCT::cut(a[x][y + 1], p);
}
inline void gao(int p) {
  static int x, y;
  for (; !check(p); ++Lr) del(Lr);
  x = b[p].first, y = b[p].second;
  if (x > 1 && a[x - 1][y] >= Lr && a[x - 1][y] < p) {
    LCT::link(a[x - 1][y], p);
    Seg::modify(rt, 1, n, 1, a[x - 1][y], 1);
  }
  if (y > 1 && a[x][y - 1] >= Lr && a[x][y - 1] < p) {
    LCT::link(a[x][y - 1], p);
    Seg::modify(rt, 1, n, 1, a[x][y - 1], 1);
  }
  if (x < R && a[x + 1][y] >= Lr && a[x + 1][y] < p) {
    LCT::link(a[x + 1][y], p);
    Seg::modify(rt, 1, n, 1, a[x + 1][y], 1);
  }
  if (y < C && a[x][y + 1] >= Lr && a[x][y + 1] < p) {
    LCT::link(a[x][y + 1], p);
    Seg::modify(rt, 1, n, 1, a[x][y + 1], 1);
  }
}
int main() {
  open("hh");
  R = rd();
  C = rd();
  for (int i = 1; i <= R; i++) {
    a[i].resize(C + 1);
    for (int j = 1; j <= C; j++) b[a[i][j] = rd()] = pair<int, int>(i, j);
  }
  n = R * C;
  Seg::build(rt, 1, n);
  Lr = 1;
  long long ans = 1;
  for (int i = 2; i <= n; i++) {
    gao(i);
    pair<int, int> res = Seg::query(rt, 1, n, Lr, i);
    ans += res.first == i ? res.second : 0;
  }
  printf("%lld\n", ans);
  return 0;
}
