#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int LG = 20;
const int M = 5e3 + 10;
int n, q;
int a[N];
struct Segment {
  int l, r;
  double p;
  Segment() {}
  Segment(int l, int r, double p) : l(l), r(r), p(p) {}
  bool operator<(const Segment &that) const {
    if (l != that.l) return l < that.l;
    return r > that.r;
  }
} segs[N];
struct RMQ {
  int n;
  int lg[N];
  int spT[N][LG + 2];
  void Init(int *a, int _n) {
    n = _n;
    for (int i = 1; i <= n; ++i) spT[i][0] = a[i];
    for (int j = 1; (1 << j) <= n; ++j)
      for (int i = 1; i + (1 << j) - 1 <= n; ++i)
        spT[i][j] = max(spT[i][j - 1], spT[i + (1 << (j - 1))][j - 1]);
    for (int i = 0; (1 << i) <= n; ++i) lg[1 << i] = i;
    for (int i = 1; i <= n; ++i)
      if (!lg[i]) lg[i] = lg[i - 1];
  }
  int Query(int l, int r) {
    int k = lg[r - l + 1];
    return max(spT[l][k], spT[r - (1 << k) + 1][k]);
  }
} RMQ;
vector<int> adj[N];
double dp[M][M];
void Seg(int p) { cout << "[" << segs[p].l << ", " << segs[p].r << "]"; }
void BuildTree() {
  vector<int> st;
  st.push_back(1);
  for (int i = 2; i <= q; ++i) {
    int l = segs[i].l, r = segs[i].r;
    while (st.size() && l > segs[st.back()].r) st.pop_back();
    assert(st.size());
    adj[st.back()].push_back(i);
    st.push_back(i);
  }
}
void DFS(int u) {
  int child = 0;
  for (int v : adj[u]) {
    DFS(v);
    ++child;
  }
  if (child == 0) {
    dp[u][0] = 1. - segs[u].p;
    for (int i = 1; i < M; ++i) dp[u][i] = 1.;
  } else {
    sort(adj[u].begin(), adj[u].end(),
         [&](int x, int y) { return segs[x].l < segs[y].l; });
    for (int j = 0; j < M; ++j) {
      double p1 = 1., p2 = 1.;
      int p = segs[u].l, val_max = 0;
      for (int v : adj[u]) {
        int k = RMQ.Query(segs[u].l, segs[u].r) -
                RMQ.Query(segs[v].l, segs[v].r) + j;
        k = min(k, M - 1);
        if (segs[v].l > p) {
          val_max = max(val_max, RMQ.Query(p, segs[v].l - 1));
        }
        p = segs[v].r + 1;
        assert(k >= 0);
        p1 *= dp[v][k];
        p2 *= (k > 0 ? dp[v][k - 1] : 0);
      }
      if (p <= segs[u].r) {
        val_max = max(val_max, RMQ.Query(p, segs[u].r));
      }
      dp[u][j] += (1. - segs[u].p) * p1;
      dp[u][j] +=
          ((j == 0 && val_max == RMQ.Query(segs[u].l, segs[u].r)) ? 0
                                                                  : segs[u].p) *
          p2;
    }
  }
}
int main() {
  cin >> n >> q;
  for (int i = 1; i <= n; ++i) cin >> a[i];
  bool has = false;
  for (int i = 1; i <= q; ++i) {
    int l, r;
    double p;
    cin >> l >> r >> p;
    if (l == 1 && r == n) has = true;
    segs[i] = Segment(l, r, p);
  }
  RMQ.Init(a, n);
  if (has == false) segs[++q] = Segment(1, n, 0);
  sort(segs + 1, segs + q + 1);
  BuildTree();
  DFS(1);
  double answer = 0;
  int val_max = RMQ.Query(1, n);
  for (int i = 0; i < M; ++i) {
    double prob = dp[1][i] - (i == 0 ? 0 : dp[1][i - 1]);
    answer += prob * (val_max + i);
  }
  cout << fixed << setprecision(10) << answer << endl;
  return 0;
}
