#include <bits/stdc++.h>
using namespace std;
int read() {
  int x = 0, f = 1;
  char ch = getchar();
  while (ch - '0' < 0 || ch - '0' > 9) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch - '0' >= 0 && ch - '0' <= 9) {
    x = x * 10 + ch - '0';
    ch = getchar();
  }
  return x * f;
}
int xx[4] = {0, 0, 1, -1};
int yy[4] = {1, -1, 0, 0};
pair<int, int> pos[200010];
int a[2010][2010];
int n, m;
vector<int> v[200010];
int bk[200010];
struct LCT {
  int fa[200010], ch[200010][2], rev[200010];
  int s[200010], top;
  int get(int x) {
    int y = fa[x];
    return (ch[y][1] == x);
  }
  bool isroot(int x) {
    int y = fa[x];
    return ch[y][get(x)] != x;
  }
  void rotate(int x) {
    int y = fa[x], z = fa[y];
    int l = get(x), r = l ^ 1;
    if (!isroot(y)) ch[z][get(y)] = x;
    fa[x] = z;
    ch[y][l] = ch[x][r];
    fa[ch[x][r]] = y;
    ch[x][r] = y;
    fa[y] = x;
  }
  void pushdown(int x) {
    if (!rev[x]) return;
    int l = ch[x][0], r = ch[x][1];
    swap(ch[x][0], ch[x][1]);
    rev[l] ^= 1;
    rev[r] ^= 1;
    rev[x] = 0;
  }
  void splay(int x) {
    top = 0;
    s[++top] = x;
    int tmp = x;
    while (!isroot(tmp)) tmp = fa[tmp], s[++top] = tmp;
    for (int i = top; i >= 1; i--) pushdown(s[i]);
    while (!isroot(x)) {
      int y = fa[x], z = fa[y];
      if (!isroot(y)) {
        if (get(x) ^ get(y))
          rotate(x);
        else
          rotate(y);
      }
      rotate(x);
    }
  }
  void access(int x) {
    int y = 0;
    while (x) {
      splay(x);
      ch[x][1] = y;
      y = x;
      x = fa[x];
    }
  }
  void makeroot(int x) {
    access(x);
    splay(x);
    rev[x] ^= 1;
  }
  int findroot(int x) {
    access(x);
    splay(x);
    while (ch[x][0]) {
      pushdown(x);
      x = ch[x][0];
    }
    splay(x);
    return x;
  }
  bool link(int x, int y) {
    if (findroot(x) == findroot(y)) return true;
    makeroot(x);
    fa[x] = y;
    return false;
  }
  void cut(int x, int y) {
    makeroot(x);
    access(y);
    splay(y);
    ch[y][0] = fa[x] = 0;
  }
  bool check(int x) {
    for (int i = 0; i < v[x].size(); i++) {
      if (bk[v[x][i]] && findroot(x) == findroot(v[x][i])) return false;
    }
    return true;
  }
} L;
int pre[200010];
bool check(int x, int y) { return (x >= 1 && x <= n && y >= 1 && y <= m); }
bool insert(int x) {
  for (int i = 0; i < v[x].size(); i++) {
    if (bk[v[x][i]]) {
      if (L.link(x, v[x][i])) {
        for (int j = 0; j < i; j++)
          if (bk[v[x][j]]) L.cut(x, v[x][j]);
        return true;
      }
    }
  }
  return false;
}
void del(int x) {
  for (int i = 0; i < v[x].size(); i++)
    if (bk[v[x][i]]) L.cut(x, v[x][i]);
}
struct Segment_Tree {
  pair<int, int> t[200010 * 4];
  int tag[200010 * 4];
  pair<int, int> merge(pair<int, int> a, pair<int, int> b) {
    pair<int, int> res = make_pair(min(a.first, b.first), 0);
    if (a.first == res.first) res.second += a.second;
    if (b.first == res.first) res.second += b.second;
    return res;
  }
  void update(int k) { t[k] = merge(t[k * 2], t[k * 2 + 1]); }
  void build(int k, int l, int r) {
    if (l == r) {
      t[k] = make_pair(0, 1);
      return;
    }
    int mid = (l + r) / 2;
    build(k * 2, l, mid);
    build(k * 2 + 1, mid + 1, r);
    update(k);
  }
  void pushdown(int k) {
    if (!tag[k]) return;
    t[k * 2].first += tag[k];
    t[k * 2 + 1].first += tag[k];
    tag[k * 2] += tag[k];
    tag[k * 2 + 1] += tag[k];
    tag[k] = 0;
  }
  void modi(int k, int l, int r, int x, int y, int z) {
    if (l >= x && r <= y) {
      t[k].first += z;
      tag[k] += z;
      return;
    }
    pushdown(k);
    int mid = (l + r) / 2;
    if (mid >= x) modi(k * 2, l, mid, x, y, z);
    if (mid < y) modi(k * 2 + 1, mid + 1, r, x, y, z);
    update(k);
  }
  pair<int, int> query(int k, int l, int r, int x, int y) {
    if (l >= x && r <= y) return t[k];
    pushdown(k);
    int mid = (l + r) / 2;
    if (mid >= x && mid >= y) return query(k * 2, l, mid, x, y);
    if (mid < y && mid < x) return query(k * 2 + 1, mid + 1, r, x, y);
    return merge(query(k * 2, l, mid, x, y),
                 query(k * 2 + 1, mid + 1, r, x, y));
  }
} S;
long long ans;
int main() {
  n = read();
  m = read();
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++)
      a[i][j] = read(), pos[a[i][j]] = make_pair(i, j);
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      for (int k = 0; k < 4; k++) {
        int tmpx = i + xx[k], tmpy = j + yy[k];
        if (check(tmpx, tmpy)) v[a[i][j]].push_back(a[tmpx][tmpy]);
      }
    }
  }
  int pos = 0;
  for (int i = 1; i <= n * m; i++) {
    while (pos < n * m) {
      pos++;
      if (insert(pos)) {
        pos--;
        break;
      }
      bk[pos] = 1;
      pre[pos] = i;
    }
    del(i);
    bk[i] = 0;
  }
  S.build(1, 1, n * m);
  for (int i = 1; i <= n * m; i++) {
    S.modi(1, 1, n * m, 1, i, 1);
    for (int j = 0; j < v[i].size(); j++) {
      if (v[i][j] < i) S.modi(1, 1, n * m, 1, v[i][j], -1);
    }
    pair<int, int> tmp = S.query(1, 1, n * m, pre[i], i);
    if (tmp.first == 1) ans += tmp.second;
  }
  printf("%lld\n", ans);
  return 0;
}
