#include <bits/stdc++.h>
using namespace std;
 
#define ll long long
#define ull unsigned long long
#define ld long double
#define pb push_back
#define ppb pop_back
#define pii pair<ll, ll>
#define pll pair<ll, ll>
#define vi vector<ll>
#define vll vector<ll>
#define vull vector<ull>
#define vpii vector<pll >
#define vpll vector<pll >
#define mp make_pair
#define mt make_tuple
#define ff first
#define ss second
#define uset unordered_set
#define umap unordered_map
#define all(x) x.begin(), x.end()
#define revall(x) x.rbegin(), x.rend()
#define rep(i, j, k) for(ll i = j; i < k; ++i)
#define fastio ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define T int tt; cin>>tt; while(tt--)
 
const ll MOD = (ll)(1e9+7);
const int inf = (int)INFINITY;
const ll INF = (ll)INFINITY;
const int MAX = (int)(1e5+1);

int x, temp[10], tree[4*MAX][10], a[MAX], lazy[4*MAX];

void build(int node, int l, int r) {
    if(l == r) {
        rep(i, 0, x) tree[node][i] = 0;
        tree[node][a[l]%x] = 1;
        return;
    }
    int m = (l + r)/2;
    build(node<<1, l, m);
    build(node<<1|1, m+1, r);
    rep(i, 0, x)
        tree[node][i] = tree[node<<1][i] + tree[node<<1|1][i];
}

inline void update_lazy(int node, int l, int r) {
    rep(i, 0, x)
        temp[(i + lazy[node])%x] = tree[node][i];
    rep(i, 0, x)
        tree[node][i] = temp[i];
    if(l != r) {
        lazy[node<<1] = (lazy[node<<1] + lazy[node])%x;
        lazy[node<<1|1] = (lazy[node<<1|1] + lazy[node])%x;
    }
    lazy[node] = 0;
}

void update(int node, int l, int r, int i, int j, int val) {
    if(lazy[node])
        update_lazy(node, l, r);
    if(j < l || i > r)
        return;
    if(i <= l && j >= r) {
        rep(i, 0, x)
            temp[(i + val)%x] = tree[node][i];
        rep(i, 0, x)
            tree[node][i] = temp[i];
        if(l != r) {
            lazy[node<<1] = (lazy[node<<1] + val)%x;
            lazy[node<<1|1] = (lazy[node<<1|1] + val)%x;
        }
        return;
    }
    int m = (l + r)/2;
    update(node<<1, l, m, i, j, val);
    update(node<<1|1, m+1, r, i, j, val); 
    rep(i, 0, x)
        tree[node][i] = tree[node<<1][i] + tree[node<<1|1][i];
}


ll query(int node, int l, int r, int i, int j) {
    if(lazy[node])
        update_lazy(node, l, r);
    if(j < l || i > r)
        return 0;
    if(i <= l && j >= r)
        return tree[node][0];
    int m = (l + r)/2;
    return query(node<<1, l, m, i, j) + query(node<<1|1, m+1, r, i, j);
}

int main() {
    fastio;
    
    int n, q;
    cin >> n >> q >> x;
	
    rep(i, 0, n) cin >> a[i];
    
    build(1, 0, n-1);
    
    while(q--) {
        int a, b, c, val;
        cin >> c >> a >> b;
        --a, --b;
        if(c == 1) {
            cin >> val;
			update(1, 0, n-1, a, b, val%x);
        } else {
            cout << query(1, 0, n-1, a, b) << '\n';
        }
    }
    return 0;
}