#include <bits/stdc++.h>
using namespace std;
template <typename Tp>
inline void read(Tp &x) {
  static char c;
  static bool neg;
  x = 0, c = getchar(), neg = false;
  for (; !isdigit(c); c = getchar()) {
    if (c == '-') {
      neg = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (neg) {
    x = -x;
  }
}
const int N = 1000 + 5;
const int M = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int dx[] = {1, 0, -1, 0}, dy[] = {0, 1, 0, -1};
namespace LCT {
struct Node {
  Node *son[2], *fa;
  bool rev;
  inline int type() {
    if (fa->son[0] == this) {
      return 0;
    } else if (fa->son[1] == this) {
      return 1;
    } else {
      return 2;
    }
  }
  inline void pushUp();
  inline void pushDown();
};
Node pool[M];
int poolCnt;
Node *null;
inline void Node::pushUp() {}
inline void Node::pushDown() {
  if (rev) {
    swap(son[0], son[1]);
    if (son[0] != null) {
      son[0]->rev ^= true;
    }
    if (son[1] != null) {
      son[1]->rev ^= true;
    }
    rev = false;
  }
}
inline void init(const int MX) {
  null = &pool[0];
  for (int i = 1; i <= MX; ++i) {
    pool[i].fa = pool[i].son[0] = pool[i].son[1] = null;
  }
}
inline void rotate(Node *now) {
  Node *fa = now->fa, *gr = fa->fa;
  int nowType = now->type(), faType;
  if (nowType == 2) {
    return;
  }
  faType = fa->type();
  fa->son[nowType] = now->son[nowType ^ 1];
  now->son[nowType ^ 1]->fa = fa;
  now->son[nowType ^ 1] = fa;
  fa->fa = now;
  if (faType != 2) {
    gr->son[faType] = now;
  }
  now->fa = gr;
  fa->pushUp();
  now->pushUp();
}
inline void splay(Node *now) {
  static Node *stack[M];
  int top = 0;
  while (now->type() != 2) {
    stack[++top] = now;
    now = now->fa;
  }
  stack[++top] = now;
  while (top != 0) {
    stack[top--]->pushDown();
  }
  now = stack[1];
  int nowType = now->type(), faType;
  while (nowType != 2) {
    Node *fa = now->fa;
    faType = fa->type();
    if (faType != 2) {
      if (nowType == faType) {
        rotate(fa);
      } else {
        rotate(now);
      }
    }
    rotate(now);
    nowType = now->type();
  }
}
inline void access(Node *now) {
  Node *prev = null;
  while (now != null) {
    splay(now);
    now->son[1] = prev;
    now->pushUp();
    prev = now;
    now = now->fa;
  }
}
inline void makeRoot(Node *now) {
  access(now);
  splay(now);
  now->rev = true;
}
inline Node *findRoot(Node *now) {
  access(now);
  splay(now);
  while (now->son[0] != null) {
    now->pushDown();
    now = now->son[0];
  }
  return now;
}
inline Node *findRoot(int id) { return findRoot(pool + id); }
inline void link(Node *u, Node *v) {
  makeRoot(u);
  if (findRoot(v) != u) {
    u->fa = v;
  }
}
inline void link(int u, int v) { link(pool + u, pool + v); }
inline void cut(Node *u, Node *v) {
  makeRoot(u);
  if (findRoot(v) == u && u->son[1] == null && u->fa == v) {
    u->fa = v->son[0] = null;
  }
}
inline void cut(int u, int v) { cut(pool + u, pool + v); }
}  // namespace LCT
namespace Seg {
struct Node {
  int min, cnt, tag;
};
Node node[M * 4];
inline void pushUp(int u) {
  node[u].min = std::min(node[((u) << 1)].min, node[((u) << 1 | 1)].min);
  node[u].cnt = 0;
  if (node[u].min == node[((u) << 1)].min) {
    node[u].cnt += node[((u) << 1)].cnt;
  }
  if (node[u].min == node[((u) << 1 | 1)].min) {
    node[u].cnt += node[((u) << 1 | 1)].cnt;
  }
}
inline void pushDown(int u) {
  if (!node[u].tag) {
    return;
  }
  node[((u) << 1)].min += node[u].tag;
  node[((u) << 1)].tag += node[u].tag;
  node[((u) << 1 | 1)].min += node[u].tag;
  node[((u) << 1 | 1)].tag += node[u].tag;
  node[u].tag = 0;
}
void build(int u, int l, int r) {
  node[u].min = 0;
  node[u].cnt = r - l + 1;
  if (l == r) {
    return;
  }
  int mid = (l + r) >> 1;
  build(((u) << 1), l, mid);
  build(((u) << 1 | 1), mid + 1, r);
  pushUp(u);
}
void update(int u, int l, int r, int ul, int ur, int x) {
  if (ul <= l && r <= ur) {
    node[u].min += x;
    node[u].tag += x;
    return;
  }
  pushDown(u);
  int mid = (l + r) >> 1;
  if (ul <= mid) {
    update(((u) << 1), l, mid, ul, ur, x);
  }
  if (mid < ur) {
    update(((u) << 1 | 1), mid + 1, r, ul, ur, x);
  }
  pushUp(u);
}
pair<int, int> query(int u, int l, int r, int ql, int qr) {
  if (qr < l || ql > r) {
    return (pair<int, int>){INF, 0};
  }
  if (ql <= l && r <= qr) {
    return (pair<int, int>){node[u].min, node[u].cnt};
  }
  pushDown(u);
  int mid = (l + r) >> 1;
  pair<int, int> res = (pair<int, int>){INF, 0}, pir;
  if (ql <= mid) {
    res = std::min(res, query(((u) << 1), l, mid, ql, qr));
  }
  if (mid < qr) {
    pir = query(((u) << 1 | 1), mid + 1, r, ql, qr);
    if (res.first > pir.first) {
      res = pir;
    } else if (res.first == pir.first) {
      res.second += pir.second;
    }
  }
  return res;
}
}  // namespace Seg
int n, m, e;
int f[N][N];
vector<int> gt[M], lt[M];
int main() {
  read(n), read(m);
  e = n * m;
  LCT::init(e);
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      read(f[i][j]);
    }
  }
  long long ans = 0;
  for (int x = 1, nx, ny; x <= n; ++x) {
    for (int y = 1; y <= m; ++y) {
      for (int i = 0; i < 4; ++i) {
        nx = x + dx[i], ny = y + dy[i];
        if (nx > 0 && nx <= n && ny > 0 && ny <= m) {
          if (f[x][y] > f[nx][ny]) {
            lt[f[x][y]].emplace_back(f[nx][ny]);
          } else {
            gt[f[x][y]].emplace_back(f[nx][ny]);
          }
        }
      }
    }
  }
  Seg::build(1, 1, e);
  int r = 0;
  for (int l = 1; l <= e; ++l) {
    bool cir = false;
    for (int nr = r + 1; nr <= e; ++nr) {
      vector<int> vec;
      for (const auto &v : lt[nr]) {
        if (v >= l) {
          if (LCT::findRoot(nr) == LCT::findRoot(v)) {
            cir = true;
            break;
          }
          LCT::link(nr, v);
          vec.emplace_back(v);
        }
      }
      for (const auto &v : vec) {
        LCT::cut(nr, v);
      }
      if (cir) {
        break;
      }
      ++r;
      int edge = 0;
      for (const auto &v : lt[nr]) {
        if (v >= l) {
          LCT::link(nr, v);
          ++edge;
        }
      }
      Seg::update(1, 1, e, nr, e, -edge);
      Seg::update(1, 1, e, nr, nr, r - l + 1);
    }
    pair<int, int> res = Seg::query(1, 1, e, l, r);
    if (res.first == 1) {
      ans += res.second;
    }
    for (const auto &v : gt[l]) {
      if (v <= r) {
        LCT::cut(l, v);
        Seg::update(1, 1, e, v, e, 1);
      }
    }
    Seg::update(1, 1, e, l, r, -1);
  }
  printf("%lld\n", ans);
  return 0;
}
