I do not think you can use std::max_elementfor such data. You can use std::accumulate():
using dvect = std::vector<double>;
using ddvect = std::vector<dvect>;
using dddvect = std::vector<ddvect>;
dddvect mx = { { { 1, 2, 3 }, { -1, 3 }, { 8,-2, 3 } },
               { {}, { -1, 25, 3 }, { 7, 3, 3 } },
               { { -1, -2, -3 }, {}, { 33 } } };
struct max_value {
    size_t i = 0;
    size_t j = 0;
    size_t k = 0;
    double value = -std::numeric_limits<double>::infinity();
    max_value() = default;
    max_value( size_t i, size_t j, size_t k, double v ) : i( i ), j( j ), k( k ), value( v ) {}
    max_value operator<<( const max_value &v ) const
    {
        return value > v.value ? *this : v;
    }
};
auto max = std::accumulate( mx.begin(), mx.end(), max_value{}, [&mx]( const max_value &val, const ddvect &ddv ) {
    auto i = std::distance( &*mx.cbegin(), &ddv );
    return std::accumulate( ddv.begin(), ddv.end(), val, [i,&ddv]( const max_value &val, const dvect &dv ) {
        auto j = std::distance( &*ddv.cbegin(), &dv );
        return std::accumulate( dv.begin(), dv.end(), val, [i,j,&dv]( const max_value &val, const double &d ) {
            auto k = std::distance( &*dv.cbegin(), &d );
            return val << max_value( i, j, k, d );
        } );
    } );
} );
living example . The code can be simplified if C ++ 14 or later is allowed, but I'm not sure if this is worse, and efforts to optimize and reorganize the data will most likely work better (you could use std::max_element()for a single vector vector, for example). On the other hand, this layout supports a gear matrix, as shown in the example (subarrays of different sizes)