#include <bits/stdc++.h>
using namespace std;
struct node {long long val,add,mul,l,r;} tree[400005];
long long n,T,mod,a[100005];
void build_tree(long long pos,long long l,long long r)
{
tree[pos].l = l;
tree[pos].r = r;
tree[pos].add = 0;
tree[pos].mul = 1;
if(l == r)
{
tree[pos].val = a[l]%mod;
return;
}
long long mid = (l+r)/2;
build_tree(pos*2,l,mid);
build_tree(pos*2+1,mid+1,r);
tree[pos].val = (tree[pos*2].val+tree[pos*2+1].val)%mod;
return;
}
long long mul(long long a,long long b) {return ((a%mod)*(b%mod))%mod;}
void update_flag(long long pos)
{
if(tree[pos].mul != 1 || tree[pos].add != 0)
{
tree[pos*2].val = mul(tree[pos*2].val,tree[pos].mul);
tree[pos*2+1].val = mul(tree[pos*2+1].val,tree[pos].mul);
tree[pos*2].val = (tree[pos*2].val+tree[pos].add*(tree[pos*2].r-tree[pos*2].l+1))%mod;
tree[pos*2+1].val = (tree[pos*2+1].val+tree[pos].add*(tree[pos*2+1].r-tree[pos*2+1].l+1))%mod;
tree[pos*2].mul = mul(tree[pos].mul,tree[pos*2].mul);
tree[pos*2+1].mul = mul(tree[pos].mul,tree[pos*2+1].mul);
tree[pos*2].add = mul(tree[pos*2].add,tree[pos].mul);
tree[pos*2+1].add = mul(tree[pos*2+1].add,tree[pos].mul);
tree[pos*2].add = (tree[pos*2].add,tree[pos].add)%mod;
tree[pos*2+1].add = (tree[pos*2+1].add+tree[pos].add)%mod;
tree[pos].mul = 1;
tree[pos].add = 0;
}
return;
}
void change(long long pos,long long l,long long r,long long add_val)
{
if(l <= tree[pos].l && r >= tree[pos].r)
{
tree[pos].val = (tree[pos].val+add_val*(tree[pos].r-tree[pos].l+1))%mod;
tree[pos].add = (tree[pos].add+add_val)%mod;
return;
}
update_flag(pos);
long long mid = (tree[pos].l+tree[pos].r)/2;
if(l <= mid) change(pos*2,l,r,add_val);
if(r > mid) change(pos*2+1,l,r,add_val);
tree[pos].val = (tree[pos*2].val+tree[pos*2+1].val)%mod;
return;
}
void change_mul(long long pos,long long l,long long r,long long mul_val)
{
if(l <= tree[pos].l && r >= tree[pos].r)
{
tree[pos].val = mul(tree[pos].val,mul_val);
tree[pos].mul = mul(tree[pos].mul,mul_val);
tree[pos].add = mul(tree[pos].add,mul_val);
return;
}
update_flag(pos);
long long mid = (tree[pos].l+tree[pos].r)/2;
if(l <= mid) change_mul(pos*2,l,r,mul_val);
if(r > mid) change_mul(pos*2+1,l,r,mul_val);
tree[pos].val = (tree[pos*2].val+tree[pos*2+1].val)%mod;
return;
}
long long get_sum(long long pos,long long l,long long r)
{
if(l <= tree[pos].l && r >= tree[pos].r) return tree[pos].val;
update_flag(pos);
long long mid = (tree[pos].l+tree[pos].r)/2,ans = 0;
if(l <= mid) ans = (ans+get_sum(pos*2,l,r))%mod;
if(r > mid) ans = (ans+get_sum(pos*2+1,l,r))%mod;
return ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> T >> mod;
for(long long i = 1;i <= n;i++) cin >> a[i];
build_tree(1,1,n);
while(T--)
{
long long op,x,y,k;
cin >> op;
if(op == 1)
{
cin >> x >> y >> k;
change(1,x,y,k%mod);
}else if(op == 2)
{
cin >> x >> y >> k;
change_mul(1,x,y,k%mod);
}else if(op == 3)
{
cin >> x >> y;
cout << get_sum(1,x,y) << '\n';
}
}
return 0;
}