#include <bits/stdc++.h>
using namespace std;
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  os << '{';
  string sep;
  for (const auto &x : v) os << sep << x, sep = ", ";
  return os << '}';
}
template <typename T, size_t size>
ostream &operator<<(ostream &os, const array<T, size> &arr) {
  os << '{';
  string sep;
  for (const auto &x : arr) os << sep << x, sep = ", ";
  return os << '}';
}
template <typename A, typename B>
ostream &operator<<(ostream &os, const pair<A, B> &p) {
  return os << '(' << p.first << ", " << p.second << ')';
}
void dbg_out() { cerr << endl; }
template <typename Head, typename... Tail>
void dbg_out(Head H, Tail... T) {
  cerr << ' ' << H;
  dbg_out(T...);
}
const int INF = 1e9 + 5;
struct segment_change {
  int to_add;
  segment_change(int _to_add = 0) : to_add(_to_add) {}
  void reset() { to_add = 0; }
  bool has_change() const { return to_add != 0; }
  segment_change combine(const segment_change &other) const {
    return segment_change(to_add + other.to_add);
  }
};
struct segment {
  int minimum, count_of_min;
  segment(int _minimum = INF, int _count_of_min = 0)
      : minimum(_minimum), count_of_min(_count_of_min) {}
  void apply(int, const segment_change &change) { minimum += change.to_add; }
  void join(const segment &other) {
    if (other.minimum < minimum)
      *this = other;
    else if (other.minimum == minimum)
      count_of_min += other.count_of_min;
  }
  void join(const segment &a, const segment &b) {
    *this = a;
    join(b);
  }
  int get_goal_count(int goal) const {
    return minimum == goal ? count_of_min : 0;
  }
};
pair<int, int> right_half[32];
struct min_count_seg_tree {
  int tree_n = 0;
  vector<segment> tree;
  vector<segment_change> changes;
  min_count_seg_tree(int n = -1) {
    if (n >= 0) init(n);
  }
  void init(int n) {
    tree_n = 1;
    while (tree_n < n) tree_n *= 2;
    tree.assign(2 * tree_n, segment());
    changes.assign(tree_n, segment_change());
  }
  void build(const vector<segment> &initial) {
    int n = int(initial.size());
    init(n);
    assert(n <= tree_n);
    for (int i = 0; i < n; i++) tree[tree_n + i] = initial[i];
    for (int position = tree_n - 1; position > 0; position--)
      tree[position].join(tree[2 * position], tree[2 * position + 1]);
  }
  void push_down(int position, int length) {
    if (!changes[position].has_change()) return;
    if (2 * position < tree_n) {
      changes[2 * position] = changes[2 * position].combine(changes[position]);
      changes[2 * position + 1] =
          changes[2 * position + 1].combine(changes[position]);
    }
    tree[2 * position].apply(length / 2, changes[position]);
    tree[2 * position + 1].apply(length / 2, changes[position]);
    changes[position].reset();
  }
  void push_all(int a, int b) {
    assert(0 <= a && a < b && b <= tree_n);
    a += tree_n;
    b += tree_n - 1;
    for (int up = 31 - __builtin_clz(tree_n); up > 0; up--) {
      int x = a >> up, y = b >> up;
      push_down(x, 1 << up);
      if (x != y) push_down(y, 1 << up);
    }
  }
  void join_and_apply(int position, int length) {
    tree[position].join(tree[2 * position], tree[2 * position + 1]);
    tree[position].apply(length, changes[position]);
  }
  void join_all(int a, int b) {
    assert(0 <= a && a < b && b <= tree_n);
    a += tree_n;
    b += tree_n - 1;
    int length = 1;
    while (a > 1) {
      a /= 2;
      b /= 2;
      length *= 2;
      join_and_apply(a, length);
      if (a != b) join_and_apply(b, length);
    }
  }
  template <typename T_range_op>
  void process_range(int a, int b, bool needs_join, T_range_op &&range_op) {
    if (a == b) return;
    push_all(a, b);
    int original_a = a, original_b = b;
    int length = 1, r_size = 0;
    for (a += tree_n, b += tree_n; a < b; a /= 2, b /= 2, length *= 2) {
      if (a & 1) range_op(a++, length);
      if (b & 1) right_half[r_size++] = {--b, length};
    }
    for (int i = r_size - 1; i >= 0; i--)
      range_op(right_half[i].first, right_half[i].second);
    if (needs_join) join_all(original_a, original_b);
  }
  segment query(int a, int b) {
    assert(0 <= a && a <= b && b <= tree_n);
    segment answer;
    process_range(a, b, false,
                  [&](int position, int) { answer.join(tree[position]); });
    return answer;
  }
  void update(int a, int b, const segment_change &change) {
    assert(0 <= a && a <= b && b <= tree_n);
    process_range(a, b, true, [&](int position, int length) {
      tree[position].apply(length, change);
      if (position < tree_n)
        changes[position] = changes[position].combine(change);
    });
  }
};
struct rectangle {
  int x1, y1, x2, y2;
};
struct rect_event {
  int x, y1, y2, change;
  bool operator<(const rect_event &other) const { return x < other.x; }
};
int64_t rectangle_union_area(const vector<rectangle> &rects) {
  if (rects.empty()) return 0;
  vector<int> Xs, Ys;
  vector<rect_event> events;
  for (const rectangle &rect : rects) {
    Xs.push_back(rect.x1);
    Xs.push_back(rect.x2);
    Ys.push_back(rect.y1);
    Ys.push_back(rect.y2);
    events.push_back({rect.x1, rect.y1, rect.y2, +1});
    events.push_back({rect.x2, rect.y1, rect.y2, -1});
  }
  sort(Xs.begin(), Xs.end());
  sort(Ys.begin(), Ys.end());
  Xs.resize(unique(Xs.begin(), Xs.end()) - Xs.begin());
  Ys.resize(unique(Ys.begin(), Ys.end()) - Ys.begin());
  int XC = int(Xs.size());
  int YC = int(Ys.size());
  int Y_range = Ys.back() - Ys.front();
  sort(events.begin(), events.end());
  int E = int(events.size());
  auto &&compress_y = [&](int y) {
    return int(lower_bound(Ys.begin(), Ys.end(), y) - Ys.begin());
  };
  min_count_seg_tree tree(YC - 1);
  vector<segment> initial(YC - 1);
  for (int i = 0; i < YC - 1; i++) initial[i] = segment(0, Ys[i + 1] - Ys[i]);
  tree.build(initial);
  int64_t area = 0;
  for (int i = 0, e = 0; i < XC - 1; i++) {
    while (e < E && events[e].x <= Xs[i]) {
      int y1 = compress_y(events[e].y1);
      int y2 = compress_y(events[e].y2);
      tree.update(y1, y2, segment_change(events[e].change));
      e++;
    }
    segment result = tree.tree[1];
    area += int64_t(Y_range - result.get_goal_count(0)) * (Xs[i + 1] - Xs[i]);
  }
  return area;
}
int N, M, NM;
vector<string> grid;
vector<int> slides_to;
vector<vector<int>> adj;
vector<int> tour_start, tour_end;
int tour;
bool valid(int r, int c) { return 0 <= r && r < N && 0 <= c && c < M; }
int key(int r, int c) { return valid(r, c) ? r * M + c : -1; };
void dfs(int node, int parent) {
  tour_start[node] = tour++;
  for (int neigh : adj[node])
    if (neigh != parent) dfs(neigh, node);
  tour_end[node] = tour;
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cin >> N >> M;
  NM = N * M;
  grid.resize(N);
  for (string &row : grid) cin >> row;
  slides_to.assign(NM, -1);
  for (int r = 0; r < N; r++)
    for (int c = 0; c < M; c++) {
      int me = key(r, c);
      switch (grid[r][c]) {
        case 'L':
          slides_to[me] = key(r, c + 2);
          break;
        case 'R':
          slides_to[me] = key(r, c - 2);
          break;
        case 'U':
          slides_to[me] = key(r + 2, c);
          break;
        case 'D':
          slides_to[me] = key(r - 2, c);
          break;
      }
    }
  adj.assign(NM, {});
  for (int i = 0; i < NM; i++)
    if (slides_to[i] >= 0) adj[slides_to[i]].push_back(i);
  tour_start.assign(NM, -1);
  tour_end.assign(NM, -1);
  tour = 0;
  for (int i = 0; i < NM; i++)
    if (slides_to[i] < 0) dfs(i, -1);
  vector<rectangle> rects;
  for (int r = 0; r < N; r++)
    for (int c = 0; c < M; c++)
      if (grid[r][c] == 'L' || grid[r][c] == 'U') {
        int key0 = key(r, c);
        int key1 = grid[r][c] == 'L' ? key(r, c + 1) : key(r + 1, c);
        if ((r + c) % 2 != 0) swap(key0, key1);
        rects.push_back({tour_start[key0], tour_start[key1], tour_end[key0],
                         tour_end[key1]});
      }
  cout << rectangle_union_area(rects) << '\n';
}
