#include <bits/stdc++.h>
#define int long long
using namespace std;
class SegmentTree {
private:
int n;
vector<int> seg, lazy;
void pushDown(int idx, int start, int end) {
if (lazy[idx] != 0) {
seg[idx] += (end - start + 1) * lazy[idx];
if (start != end) {
lazy[idx * 2] += lazy[idx];
lazy[idx * 2 + 1] += lazy[idx];
}
lazy[idx] = 0;
}
}
void updateRange(int idx, int start, int end, int l, int r, int val) {
pushDown(idx, start, end);
if (start > r || end < l) return;
if (l <= start && end <= r) {
lazy[idx] += val;
pushDown(idx, start, end);
return;
}
int mid = (start + end) >> 1;
updateRange(idx * 2, start, mid, l, r, val);
updateRange(idx * 2 + 1, mid + 1, end, l, r, val);
seg[idx] = seg[idx * 2] + seg[idx * 2 + 1];
}
int queryPoint(int idx, int start, int end, int pos) {
pushDown(idx, start, end);
if (start == end) return seg[idx];
int mid = (start + end) >> 1;
if (pos <= mid) return queryPoint(idx * 2, start, mid, pos);
else return queryPoint(idx * 2 + 1, mid + 1, end, pos);
}
public:
SegmentTree(int n) : n(n) {
seg.assign(4 * n, 0);
lazy.assign(4 * n, 0);
}
void update(int l, int r, int val) {
updateRange(1, 1, n, l, r, val);
}
int query(int pos) {
return queryPoint(1, 1, n, pos);
}
};
inline int triangular(int x) {
return x * (x + 1) / 2;
}
void updateAnswer(set<pair<int, int>>& palindromes, pair<int, int> marker,
bool isInserting, int& answer, int n) {
if (marker.second - marker.first == 2) {
answer += isInserting ? -1 : 1;
}
auto it = palindromes.find(marker);
if (!isInserting) {
auto before = it;
auto after = next(it);
bool isFirst = (it == palindromes.begin());
bool isLast = (after == palindromes.end());
auto curr = *it;
if (isFirst) {
if (isLast) {
answer = triangular(n);
} else {
auto afterVal = *after;
answer -= triangular(curr.second - 1);
answer -= triangular(afterVal.second - 1 - curr.first);
answer += triangular(afterVal.second - 1);
}
} else {
before--;
auto beforeVal = *before;
if (isLast) {
answer -= triangular(n - curr.first);
answer -= triangular(curr.second - 1 - beforeVal.first);
answer += triangular(n - beforeVal.first);
} else {
auto afterVal = *after;
answer -= triangular(curr.second - 1 - beforeVal.first);
answer -= triangular(afterVal.second - 1 - curr.first);
answer += triangular(afterVal.second - 1 - beforeVal.first);
}
}
palindromes.erase(it);
} else {
palindromes.insert(marker);
it = palindromes.find(marker);
auto curr = *it;
bool isFirst = (it == palindromes.begin());
auto after = next(it);
bool isLast = (after == palindromes.end());
if (isFirst) {
if (isLast) {
answer -= triangular(n);
answer += triangular(curr.second - 1);
answer += triangular(n - curr.first);
} else {
auto afterVal = *after;
answer += triangular(curr.second - 1);
answer += triangular(afterVal.second - 1 - curr.first);
answer -= triangular(afterVal.second - 1);
}
} else {
auto before = prev(it);
auto beforeVal = *before;
if (isLast) {
answer += triangular(n - curr.first);
answer += triangular(curr.second - 1 - beforeVal.first);
answer -= triangular(n - beforeVal.first);
} else {
auto afterVal = *after;
answer += triangular(curr.second - 1 - beforeVal.first);
answer += triangular(afterVal.second - 1 - curr.first);
answer -= triangular(afterVal.second - 1 - beforeVal.first);
}
}
}
}
void checkPalindromes(int pos, int n, SegmentTree& st, set<pair<int, int>>& palindromes,
set<pair<int, int>>& toRemove, set<pair<int, int>>& toAdd) {
if (pos <= n-1) {
bool isPalindrome = (st.query(pos) == st.query(pos+1));
bool inSet = (palindromes.find({pos, pos+1}) != palindromes.end());
if (isPalindrome && !inSet) {
toAdd.insert({pos, pos+1});
} else if (!isPalindrome && inSet) {
toRemove.insert({pos, pos+1});
}
}
if (pos <= n-2) {
bool isPalindrome = (st.query(pos) == st.query(pos+2) &&
st.query(pos) != st.query(pos+1));
bool inSet = (palindromes.find({pos, pos+2}) != palindromes.end());
if (isPalindrome && !inSet) {
toAdd.insert({pos, pos+2});
} else if (!isPalindrome && inSet) {
toRemove.insert({pos, pos+2});
}
}
}
void solve() {
int n, q;
cin >> n >> q;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
SegmentTree st(n+1);
for (int i = 1; i <= n; i++) {
st.update(i, i, a[i-1]);
}
set<pair<int, int>> palindromes;
for (int i = 1; i <= n; i++) {
if (i <= n-1 && st.query(i) == st.query(i+1)) {
palindromes.insert({i, i+1});
}
else if (i <= n-2 && st.query(i) == st.query(i+2) && st.query(i) != st.query(i+1)) {
palindromes.insert({i, i+2});
}
}
int answer = 0;
if (palindromes.empty()) {
answer = triangular(n);
} else {
int prevEnd = 0;
for (auto it = palindromes.begin(); it != palindromes.end(); it++) {
if (it == palindromes.begin()) {
answer += triangular(it->second - 1);
} else {
auto prevIt = prev(it);
answer += triangular(it->second - 1 - prevIt->first);
}
if (it->second - it->first == 2) answer--;
prevEnd = it->first;
}
if (!palindromes.empty()) {
auto last = palindromes.rbegin();
answer += triangular(n - last->first);
}
}
while (q--) {
int l, r, x;
cin >> l >> r >> x;
st.update(l, r, x);
set<pair<int, int>> toRemove, toAdd;
for (int i = max(l-2, 1LL); i <= min(l+2, n); i++) {
checkPalindromes(i, n, st, palindromes, toRemove, toAdd);
}
for (int i = max(r-2, 1LL); i <= min(r+2, n); i++) {
checkPalindromes(i, n, st, palindromes, toRemove, toAdd);
}
for (const auto& marker : toRemove) {
updateAnswer(palindromes, marker, false, answer, n);
}
for (const auto& marker : toAdd) {
updateAnswer(palindromes, marker, true, answer, n);
}
cout << answer << endl;
}
}
int32_t main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
while (t--) {
solve();
}
return 0;
}