#include <bits/stdc++.h>
using namespace std;
struct LCT {
  int ch[1000000][3], fa[1000000], turn[1000000];
  int Get(int x) { return ch[fa[x]][1] == x; }
  int nroot(int x) { return ch[fa[x]][1] == x || ch[fa[x]][0] == x; }
  void pushr(int x) {
    if (!x) return;
    swap(ch[x][0], ch[x][1]);
    turn[x] ^= 1;
  }
  void pushdown(int x) {
    if (turn[x]) {
      pushr(ch[x][0]), pushr(ch[x][1]);
      turn[x] = 0;
    }
  }
  void pushall(int x) {
    if (nroot(x)) pushall(fa[x]);
    pushdown(x);
  }
  void rotate(int x) {
    int y = fa[x], z = fa[y], w = Get(x);
    if (nroot(y)) ch[z][ch[z][1] == y] = x;
    ch[y][w] = ch[x][w ^ 1];
    if (ch[y][w]) fa[ch[y][w]] = y;
    ch[x][w ^ 1] = y;
    fa[y] = x;
    fa[x] = z;
  }
  void splay(int x) {
    pushall(x);
    while (nroot(x)) {
      int y = fa[x];
      if (nroot(y)) Get(x) ^ Get(y) ? rotate(x) : rotate(y);
      rotate(x);
    }
  }
  void access(int x) {
    for (int y = 0; x; x = fa[y = x]) {
      splay(x);
      ch[x][1] = y;
    }
  }
  int findroot(int x) {
    access(x);
    splay(x);
    while (ch[x][0]) x = ch[x][0];
    splay(x);
    return x;
  }
  void makeroot(int x) {
    access(x);
    splay(x);
    pushr(x);
    return;
  }
  int link(int x, int y) {
    makeroot(x);
    if (findroot(y) == x) return false;
    fa[x] = y;
    return true;
  }
  void cut(int x, int y) {
    makeroot(x);
    if (findroot(y) == x && fa[y] == x && !ch[y][0]) {
      fa[y] = ch[x][1] = 0;
    }
    return;
  }
} T;
struct segment_tree {
  int Min[4 * 1000000], Num[4 * 1000000], lazy[4 * 1000000];
  void pushdown(int x) {
    if (lazy[x]) {
      lazy[x << 1] += lazy[x];
      lazy[x << 1 | 1] += lazy[x];
      Min[x << 1] += lazy[x], Min[x << 1 | 1] += lazy[x];
      lazy[x] = 0;
    }
  }
  void pushup(int x) {
    if (Min[x << 1] < Min[x << 1 | 1])
      Min[x] = Min[x << 1], Num[x] = Num[x << 1];
    if (Min[x << 1] > Min[x << 1 | 1])
      Min[x] = Min[x << 1 | 1], Num[x] = Num[x << 1 | 1];
    if (Min[x << 1] == Min[x << 1 | 1])
      Min[x] = Min[x << 1], Num[x] = Num[x << 1] + Num[x << 1 | 1];
  }
  void build(int x, int l, int r) {
    if (l == r) {
      Min[x] = 0, Num[x] = 1;
      return;
    }
    int mid = l + r >> 1;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
    pushup(x);
  }
  void modify(int x, int l, int r, int ll, int rr, int k) {
    if (ll <= l && r <= rr) {
      lazy[x] += k;
      Min[x] += k;
      return;
    }
    pushdown(x);
    int mid = l + r >> 1;
    if (ll <= mid) modify(x << 1, l, mid, ll, rr, k);
    if (rr > mid) modify(x << 1 | 1, mid + 1, r, ll, rr, k);
    pushup(x);
  }
  int query(int x, int l, int r, int ll, int rr) {
    if (l == ll && r == rr) {
      if (Min[x] == 1)
        return Num[x];
      else
        return 0;
    }
    int mid = l + r >> 1;
    pushdown(x);
    if (rr <= mid)
      return query(x << 1, l, mid, ll, rr);
    else if (ll > mid)
      return query(x << 1 | 1, mid + 1, r, ll, rr);
    else
      return query(x << 1, l, mid, ll, mid) +
             query(x << 1 | 1, mid + 1, r, mid + 1, rr);
  }
} S;
vector<int> V[1000000];
int dx[10] = {1, 0, -1, 0};
int dy[10] = {0, 1, 0, -1};
int n, m, w[3000][3000];
long long ans = 0;
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++) scanf("%d", &w[i][j]);
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      for (int d = 0; d < 4; d++) {
        int x = i + dx[d], y = j + dy[d];
        if (x < 1 || y < 1 || x > n || y > m) continue;
        if (w[x][y] > w[i][j]) continue;
        V[w[x][y]].push_back(w[i][j]);
        V[w[i][j]].push_back(w[x][y]);
      }
    }
  }
  int R = 0;
  long long t = n * m;
  S.build(1, 1, t);
  for (int i = 1; i <= t; i++) {
    for (int j = R + 1; j <= t; j++) {
      int now = j, flag = 0;
      for (int d = 0; d < V[now].size(); d++) {
        int now1 = V[now][d];
        if (now1 < now && now1 >= i)
          if (!T.link(now1, now)) {
            flag = 1;
            break;
          }
      }
      for (int d = 0; d < V[now].size(); d++) T.cut(now, V[now][d]);
      if (flag == 1) break;
      R = j;
      int tot = 0;
      for (int d = 0; d < V[now].size(); d++) {
        int now1 = V[now][d];
        if (now1 < j && now1 >= i) T.link(now1, now);
        if (now1 < j && now1 >= i) tot++;
      }
      S.modify(1, 1, t, R, R, R - i + 1);
      S.modify(1, 1, t, R, t, -tot);
    }
    ans += 1ll * S.query(1, 1, t, i, R);
    int tot = 0;
    for (int d = 0; d < V[i].size(); d++) {
      if (V[i][d] <= R && V[i][d] > i) {
        T.cut(V[i][d], i);
        S.modify(1, 1, t, V[i][d], t, 1);
      }
    }
    S.modify(1, 1, t, i, R, -1);
  }
  printf("%lld\n", ans);
  return 0;
}
