#include <bits/stdc++.h>
using namespace std;
template <class T, class U>
void ckmin(T &a, U b) {
  if (a > b) a = b;
}
template <class T, class U>
void ckmax(T &a, U b) {
  if (a < b) a = b;
}
int N, M, K;
vector<int> grid[1013];
pair<int, int> coor[200013];
int lazy[3 * 200013];
pair<int, int> stor[3 * 200013];
int pos[200013];
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};
long long ans;
struct node {
  node *c[2], *p;
  bool rev;
  node() : p(NULL), rev(0) { memset(c, 0, sizeof c); }
  void flag_rev() {
    rev ^= 1;
    swap(c[0], c[1]);
  }
  void push_down() {
    if (rev) {
      for (auto i = (0); i < (2); i++)
        if (c[i]) c[i]->flag_rev();
      rev = 0;
    }
  }
  int get_pos() {
    if (!this || !p) return 2;
    for (auto i = (0); i < (2); i++)
      if (p->c[i] == this) return i;
    return 2;
  }
  bool is_root() { return get_pos() >= 2; }
  void setc(node *u, const int &v) {
    if (this && v < 2) c[v] = u;
    if (u) u->p = this;
  }
  void rotate() {
    node *_p = this->p;
    bool mark = get_pos();
    _p->p->setc(this, _p->get_pos());
    _p->setc(c[mark ^ 1], mark);
    setc(_p, mark ^ 1);
  }
  void relax() {
    static node *tmp[200013];
    int top = 0;
    node *u = this;
    while (!u->is_root()) tmp[top++] = u, u = u->p;
    u->push_down();
    while (top) tmp[--top]->push_down();
  }
  void splay() {
    relax();
    for (; !is_root(); rotate())
      if (!p->is_root())
        ((p->p->c[0] == p) == (p->c[0] == this) ? p : this)->rotate();
  }
  node *access() {
    node *u = this, *v = NULL;
    for (; u; v = u, u = u->p) u->splay(), u->setc(v, 1);
    splay();
    return v;
  }
  void be_root() {
    access();
    flag_rev();
  }
};
node lct[200013];
bool conn(node *u, node *v) {
  u->be_root(), v->access();
  return u->is_root() == 0;
}
void link(node *u, node *v) {
  u->be_root(), v->access();
  u->p = v;
  u->access();
}
void cut(node *u, node *v) {
  u->be_root(), v->access();
  v->setc(NULL, 0);
  u->p = NULL;
}
pair<int, int> comb(pair<int, int> a, pair<int, int> b) {
  if (a.first > b.first) swap(a, b);
  if (a.first == b.first) a.second += b.second;
  return a;
}
void build(int w, int L, int R) {
  if (L == R) {
    stor[w] = {1 - L, 1};
    return;
  }
  int mid = (L + R) >> 1;
  build(w << 1, L, mid);
  build(w << 1 | 1, mid + 1, R);
  stor[w] = comb(stor[w << 1], stor[w << 1 | 1]);
}
void push(int w, int L, int R) {
  if (lazy[w] == 0) return;
  stor[w].first += lazy[w];
  if (L != R) {
    lazy[w << 1] += lazy[w];
    lazy[w << 1 | 1] += lazy[w];
  }
  lazy[w] = 0;
  return;
}
void update(int w, int L, int R, int a, int b, int v) {
  push(w, L, R);
  if (b < L || R < a) return;
  if (a <= L && R <= b) {
    lazy[w] += v;
    push(w, L, R);
    return;
  }
  int mid = (L + R) >> 1;
  update(w << 1, L, mid, a, b, v);
  update(w << 1 | 1, mid + 1, R, a, b, v);
  stor[w] = comb(stor[w << 1], stor[w << 1 | 1]);
}
pair<int, int> query(int w, int L, int R, int a, int b) {
  push(w, L, R);
  if (a <= L && R <= b) {
    return stor[w];
  }
  int mid = (L + R) >> 1;
  if (b <= mid) return query(w << 1, L, mid, a, b);
  if (mid < a) return query(w << 1 | 1, mid + 1, R, a, b);
  return comb(query(w << 1, L, mid, a, b), query(w << 1 | 1, mid + 1, R, a, b));
}
int32_t main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout << fixed << setprecision(12);
  cerr << fixed << setprecision(4);
  cin >> N >> M;
  K = N * M;
  for (auto i = (0); i < (N); i++) {
    grid[i].resize(M);
  }
  for (auto i = (0); i < (N); i++) {
    for (auto j = (0); j < (M); j++) {
      cin >> grid[i][j];
      grid[i][j]--;
      coor[grid[i][j]] = {i, j};
    }
  }
  pos[K] = K;
  for (auto i = (K)-1; i >= (0); i--) {
    pos[i] = pos[i + 1];
    vector<int> guys;
    while (pos[i] > 0) {
      guys.clear();
      for (auto j = (0); j < (4); j++) {
        int x = coor[pos[i] - 1].first + dx[j],
            y = coor[pos[i] - 1].second + dy[j];
        if (x < 0 || x >= N || y < 0 || y >= M || grid[x][y] > i ||
            grid[x][y] < pos[i] - 1)
          continue;
        guys.push_back(grid[x][y]);
      }
      bool ded = false;
      for (auto i = (0); i < (((int)((guys).size()))); i++) {
        int u = guys[i];
        for (auto j = (i + 1); j < (((int)((guys).size()))); j++) {
          int v = guys[j];
          if (conn(&lct[u], &lct[v])) {
            ded = true;
          }
        }
      }
      if (ded) break;
      pos[i]--;
      for (int u : guys) {
        link(&lct[u], &lct[pos[i]]);
      }
    }
    guys.clear();
    for (auto j = (0); j < (4); j++) {
      int x = coor[i].first + dx[j], y = coor[i].second + dy[j];
      if (x < 0 || x >= N || y < 0 || y >= M || grid[x][y] > i ||
          grid[x][y] < pos[i])
        continue;
      guys.push_back(grid[x][y]);
    }
    for (int u : guys) {
      cut(&lct[u], &lct[i]);
    }
  }
  build(1, 0, K - 1);
  for (auto i = (0); i < (K); i++) {
    for (auto j = (0); j < (4); j++) {
      int x = coor[i].first + dx[j], y = coor[i].second + dy[j];
      if (x < 0 || x >= N || y < 0 || y >= M || grid[x][y] > i) continue;
      update(1, 0, K - 1, 0, grid[x][y], -1);
    }
    pair<int, int> p = query(1, 0, K - 1, pos[i], i);
    ans += p.second;
    update(1, 0, K - 1, 0, K - 1, 1);
  }
  cout << ans << '\n';
  return 0;
}
