#include <bits/stdc++.h>
using namespace std;
const int NM_MAX = 200000;
const int INF = INT_MAX / 2;
int n, m;
vector<vector<char>> input;
int encode(int r, int c) { return r * m + c; }
int dominoID[NM_MAX];
bool parity[NM_MAX];
int cnt[2];
int parent[NM_MAX];
vector<int> sons[NM_MAX];
void addEdge(int u, int v) {
  parent[u] = v;
  sons[v].push_back(u);
}
int EulerID[NM_MAX], maxEulerID[NM_MAX];
int currID;
void buildEuler(int u) {
  EulerID[u] = ++currID;
  maxEulerID[u] = EulerID[u];
  for (int v : sons[u]) {
    buildEuler(v);
    maxEulerID[u] = max(maxEulerID[u], maxEulerID[v]);
  }
}
int dominoPos[NM_MAX];
struct SGTNode {
  int minVal;
  int cntMin;
  int lazy;
};
SGTNode operator+(const SGTNode &u, const SGTNode &v) {
  SGTNode uv;
  uv.minVal = min(u.minVal, v.minVal);
  uv.cntMin = 0;
  if (u.minVal == uv.minVal) uv.cntMin += u.cntMin;
  if (v.minVal == uv.minVal) uv.cntMin += v.cntMin;
  uv.lazy = 0;
  return uv;
}
void add(SGTNode &u, int uval) {
  u.minVal += uval;
  u.lazy += uval;
}
SGTNode SGT[NM_MAX * 4 + 2];
void split(int node) {
  int lSon = node * 2, rSon = node * 2 + 1;
  add(SGT[lSon], SGT[node].lazy);
  add(SGT[rSon], SGT[node].lazy);
  SGT[node].lazy = 0;
}
void build(int node, int l, int r) {
  if (l == r) {
    SGT[node].minVal = 0;
    SGT[node].cntMin = 1;
    SGT[node].lazy = 0;
    return;
  }
  int mid = (l + r) / 2, lSon = node * 2, rSon = node * 2 + 1;
  build(lSon, l, mid);
  build(rSon, mid + 1, r);
  SGT[node] = SGT[lSon] + SGT[rSon];
}
void update(int node, int l, int r, int ul, int ur, int uval) {
  if (ul <= l && r <= ur) {
    add(SGT[node], uval);
    return;
  }
  split(node);
  int mid = (l + r) / 2, lSon = node * 2, rSon = node * 2 + 1;
  if (ul <= mid) update(lSon, l, mid, ul, ur, uval);
  if (mid + 1 <= ur) update(rSon, mid + 1, r, ul, ur, uval);
  SGT[node] = SGT[lSon] + SGT[rSon];
}
int query() {
  if (SGT[1].minVal == 0)
    return SGT[1].cntMin;
  else
    return 0;
}
long long answer;
void solve(int u) {
  int aux = dominoPos[dominoID[u]];
  update(1, 1, cnt[0], EulerID[aux], maxEulerID[aux], +1);
  answer += query();
  for (int v : sons[u]) solve(v);
  update(1, 1, cnt[0], EulerID[aux], maxEulerID[aux], -1);
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> m;
  input = vector<vector<char>>(n, vector<char>(m));
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++) cin >> input[i][j];
  int currDomino = 0;
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
      if (dominoID[encode(i, j)] == 0) {
        dominoID[encode(i, j)] = ++currDomino;
        if (input[i][j] == 'U') dominoID[encode(i + 1, j)] = currDomino;
        if (input[i][j] == 'L') dominoID[encode(i, j + 1)] = currDomino;
      }
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
      if ((i + j) % 2 == 0)
        dominoPos[dominoID[encode(i, j)]] = encode(i, j);
      else
        parity[encode(i, j)] = 1;
  for (int u = 0; u < n * m; u++) cnt[parity[u]]++;
  for (int u = 0; u < n * m; u++) parent[u] = -1;
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++) {
      if (input[i][j] == 'U' && i + 2 < n)
        addEdge(encode(i, j), encode(i + 2, j));
      if (input[i][j] == 'D' && 0 <= i - 2)
        addEdge(encode(i, j), encode(i - 2, j));
      if (input[i][j] == 'L' && j + 2 < m)
        addEdge(encode(i, j), encode(i, j + 2));
      if (input[i][j] == 'R' && 0 <= j - 2)
        addEdge(encode(i, j), encode(i, j - 2));
    }
  for (int u = 0; u < n * m; u++)
    if (parity[u] == 0 && parent[u] == -1) buildEuler(u);
  build(1, 1, cnt[0]);
  for (int u = 0; u < n * m; u++)
    if (parity[u] == 1 && parent[u] == -1) solve(u);
  answer = 1LL * cnt[0] * cnt[1] - answer;
  cout << answer << "\n";
  return 0;
}
