// This solution doesn't use walk on segment tree, slower
#include <bits/stdc++.h>
using namespace std;
#define task "main"
#define F first
#define S second
#define ii pair<int, int>
#define il pair<int, long long>
#define li pair<long long, int>
#define FOR(i, a, b) for(int i = (a); i <= (b); ++i)
#define FOD(i, b, a) for(int i = (b); i >= (a); --i)
template <class T1, class T2>
    bool maximize(T1 &a, T2 b){
        if (a < b) {a = b; return true;}
        return false;
    }
template <class T1, class T2>
    bool minimize(T1 &a, T2 b){
        if (a > b) {a = b; return true;}
        return false;
    }
template <class T>
    void printArr(T container, string separator = " ", string finish = "\n", ostream &out = cout){
        for(auto item: container) out << item << separator;
        out << finish;
    }
const int MAX_N = (int)1e5 + 5;
int n, q;
int a[MAX_N];
struct NODE {
    long long ans;
    int l, r;
    int szLeft, szRight;
    ii leftGCD[32], rightGCD[32]; // positions that change the value of GCD, start from left/right
    NODE(int pos = 0, int val = 0) {
        l = r = pos;
        szLeft = szRight = 1;
        ans = (val > 1);
        leftGCD[1] = {pos, val};
        rightGCD[1] = {pos, val};
        leftGCD[2] = {pos + 1, 1};
        rightGCD[2] = {pos - 1, 1};
    }
    NODE operator + (const NODE &other) {
        if (l == -1 && r == -1) return other;
        if (other.l == -1 && other.r == -1) return (*this);
        // initialize
        NODE res;
        res.l = l;
        res.r = other.r;
        res.ans = ans + other.ans;
        res.szLeft = szLeft;
        res.szRight = other.szRight;
        FOR(i, 1, szLeft) res.leftGCD[i] = leftGCD[i];
        FOR(i, 1, other.szRight) res.rightGCD[i] = other.rightGCD[i];
        // compute additional answer
        FOD(i, szRight, 1) {
            int j = 1;
            while (j <= other.szLeft && __gcd(rightGCD[i].S, other.leftGCD[j].S) > 1)
                j++;
            res.ans += 1LL * (rightGCD[i].F - rightGCD[i + 1].F) * (other.leftGCD[j].F - other.leftGCD[1].F);
        }
        // add new values to leftGCD/rightGCD
        FOR(i, 1, other.szLeft) {
            int newVal = __gcd(res.leftGCD[res.szLeft].S, other.leftGCD[i].S);
            if (newVal != res.leftGCD[res.szLeft].S)
                res.leftGCD[++res.szLeft] = {other.leftGCD[i].F, newVal};
        }
        FOR(i, 1, szRight) {
            int newVal = __gcd(res.rightGCD[res.szRight].S, rightGCD[i].S);
            if (newVal != res.rightGCD[res.szRight].S)
                res.rightGCD[++res.szRight] = {rightGCD[i].F, newVal};
        }
        res.leftGCD[res.szLeft + 1] = {res.r + 1, 1};
        res.rightGCD[res.szRight + 1] = {res.l - 1, 1};
        return res;
    }
};
struct IT {
    NODE tree[4 * MAX_N];
    void build(int id, int l, int r) {
        if (l == r) {
            tree[id] = NODE(l, a[l]);
            return;
        }
        int mid = (l + r) >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
        tree[id] = tree[id << 1] + tree[id << 1 | 1];
    }
    void update(int id, int l, int r, int pos, int val) {
        if (l > pos || r < pos) return;
        if (l == r) {
            tree[id] = NODE(pos, val);
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) update(id << 1, l, mid, pos, val);
        else update(id << 1 | 1, mid + 1, r, pos, val);
        tree[id] = tree[id << 1] + tree[id << 1 | 1];
    }
    NODE get(int id, int l, int r, int u, int v) {
        if (l > v || r < u) return NODE(-1, -1);
        if (l >= u && r <= v) return tree[id];
        int mid = (l + r) >> 1;
        return get(id << 1, l, mid, u, v) + get(id << 1 | 1, mid + 1, r, u, v);
    }
    void update(int pos, int val) {
        update(1, 1, n, pos, val);
    }
    long long get(int l, int r) {
        return get(1, 1, n, l, r).ans;
    }
} magic;
void solve() {
    cin >> n >> q;
    FOR(i, 1, n) cin >> a[i];
    magic.build(1, 1, n);
    while (q--) {
        int t, x, y;
        cin >> t >> x >> y;
        if (t == 1) magic.update(x, y);
        else cout << magic.get(x, y) << "\n";
    }
}
int32_t main() {
    if (fopen(task".inp", "r")) {
        freopen(task".inp", "r", stdin);
        freopen(task".out", "w", stdout);
    }
    ios_base::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    bool multitest = 0;
    int numTest = 1;
    if (multitest) cin >> numTest;
    while (numTest--) {
        solve();
    }
    return 0;
}
/* Lak lu theo dieu nhac!!!! */
Compilation message (stderr)
garaza.cpp: In function 'int32_t main()':
garaza.cpp:151:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  151 |         freopen(task".inp", "r", stdin);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
garaza.cpp:152:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  152 |         freopen(task".out", "w", stdout);
      |         ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |