#include <bits/stdc++.h>

using namespace std;

///----------------------------------------------------------

const int BS = ( 1 << 20 );
char buffer[BS];
int position = BS;

inline char getChar()
{
    if ( position == BS )
    {
        position = 0;
        fread( buffer, BS, 1, stdin );
    }

    return buffer[ position++ ];
}

inline int getNr()
{
    int nr = 0;
    char ch;

    do
    {
        ch = getChar();

    } while ( !isdigit( ch ) );

    do
    {
        nr = nr * 10 + ch - '0';
        ch = getChar();

    } while ( isdigit( ch ) );

    return nr;
}

///----------------------------------------------------------

class SegmentTree
{
public:

    SegmentTree(){}

    SegmentTree( const int _N )
    {
        N = _N;
        A = vector<long long>( 4 * N, 0 );
        lazy = vector<long long>( 4 * N, 0 );
    }

    SegmentTree( const int _N, const vector<int>&v )
    {
        N = _N;
        A = vector<long long>( 4 * N );
        lazy = vector<long long>( 4 * N );

        build( 1, 0, N - 1, v );
    }

    ~SegmentTree()
    {
        A.clear();
        lazy.clear();
    }

    void eraseTree()
    {
        A.clear();
        lazy.clear();
    }

    void copiere( const SegmentTree &T )
    {
        for ( int i = 0; i < 4 * N; ++i )
        {
            A[i] = T.A[i];
            lazy[i] = T.lazy[i];
        }
    }

    long long real_value( int nod, int st, int dr )
    {
        return A[nod] + 1LL * ( dr - st + 1 ) * lazy[nod];
    }

    void build( int nod, int st, int dr, const vector<int>&v )
    {
        if ( st == dr )
            A[nod] = v[st];
        else
        {
            int m = ( st + dr ) / 2;

            build( 2 * nod, st, m, v );
            build( 2 * nod + 1, m + 1, dr, v );

            A[nod] = real_value( 2 * nod, st, m ) + real_value( 2 * nod + 1, m + 1, dr );
        }
    }

    void propaga( int nod )
    {
        lazy[2 * nod] += lazy[nod];
        lazy[2 * nod + 1] += lazy[nod];
        A[nod] += lazy[nod];
        lazy[nod] = 0;
    }

    void update( int x, int y, long long v )
    {
        update( 1, 0, N - 1, x - 1, y - 1, v );
    }

    long long query( int x, int y )
    {
        return query( 1, 0, N - 1, x - 1, y - 1 );
    }

    void update( int nod, int st, int dr, int st_q, int dr_q, long long v )
    {
        if ( st_q <= st && dr <= dr_q )
        {
            lazy[nod] += v;
        }
        else
        {
            propaga( nod );

            int m = ( st + dr ) / 2;

            if ( st_q <= m )
                update( 2 * nod, st, m, st_q, dr_q, v );

            if ( m < dr_q )
                update( 2 * nod + 1, m + 1, dr, st_q, dr_q, v );

            A[nod] = real_value( 2 * nod, st, m ) + real_value( 2 * nod + 1, m + 1, dr );
        }
    }

    long long query( int nod, int st, int dr, int st_q, int dr_q )
    {
        if ( st_q <= st && dr <= dr_q )
        {
            return real_value( nod, st, dr );
        }
        else
        {
            propaga( nod );

            long long sum = 0;
            int m = ( st + dr ) / 2;

            if ( st_q <= m )
                sum += query( 2 * nod, st, m, st_q, dr_q );

            if ( m < dr_q )
                sum += query( 2 * nod + 1, m + 1, dr, st_q, dr_q );

            A[nod] = real_value( 2 * nod, st, m ) + real_value( 2 * nod + 1, m + 1, dr );

            return sum;
        }
    }

private:

    int N;

    vector <long long> A;
    vector <long long> lazy;

};

class Query
{
public:

    int V, L, R;

    Query( int v = 0, int l = 0, int r = 0 )
    {
        V = v;
        L = l;
        R = r;
    }
};

const int Nmax = 1e5 + 2;
const int RADICAL = 500;

int N, M;
int P, X, Y, V, Z, T;
int L, R, I, J;
long long S;

vector <int> A;
int saved[Nmax];
int tata[Nmax], depth[Nmax];
Query queryNode[Nmax];
SegmentTree STs[Nmax];
int indiceTown;

void init()
{
    indiceTown = 1;
    saved[1] = 1;
    tata[1] = 0;
    depth[1] = 1;

    STs[1] = SegmentTree( M, A );
}

long long intrebare()
{
    indiceTown++;

    tata[indiceTown] = P;
    depth[indiceTown] = depth[P] + 1;

    int father = P;

    vector <int> path;
    path.push_back( father );

    while ( !saved[father] ) /// caut un nod din arbore cu AIB in el
    {
        father = tata[father];
        path.push_back( father );
    }

    reverse( path.begin(), path.end() );

    SegmentTree auxiliarTree( M );
    auxiliarTree.copiere( STs[ path[0] ] );

    for ( int i = 1; i < path.size(); ++i )
    {
        if ( queryNode[ path[i] ].V != 0 )
            auxiliarTree.update( queryNode[ path[i] ].L, queryNode[ path[i] ].R, queryNode[ path[i] ].V );
    }

    auxiliarTree.update( L, R, V );

    if ( depth[indiceTown] % RADICAL == 1 ) /// creez in indiceTown un AIB
    {
        saved[indiceTown] = 1;
        STs[indiceTown] = SegmentTree( M );
        STs[indiceTown].copiere( auxiliarTree );
    }
    else
    {
        queryNode[indiceTown] = Query( V, L, R );
    }

    long long sum = auxiliarTree.query( I, J );

    auxiliarTree.eraseTree();

    return sum;
}

int main()
{
    ///freopen("data.in", "r", stdin);

    N = getNr(); M = getNr();

    for ( int i = 1; i <= M; ++i )
    {
        int x = getNr();
        A.push_back( x );
    }

    init();

    for ( int k = 2; k <= N; ++k )
    {
        P = getNr();
        X = getNr();
        Y = getNr();
        V = getNr();
        Z = getNr();
        T = getNr();

        ///cerr << X + S << " " << Y + S << " " << Z + S << " " << T + S << ":::: ";

        L = ( ( 1LL * X + S ) ) % M + 1;
        R = ( ( 1LL * Y + S ) ) % M + 1;
        I = ( ( 1LL * Z + S ) ) % M + 1;
        J = ( ( 1LL * T + S ) ) % M + 1;

        ///cerr << L << " " << R << " " << V << " " << I << " " << J << " " ;

        S = intrebare();

        cout << S << "\n";
    }

    ///cerr << queryNode[2].L;

    return 0;
}

/**
class BinaryIndexedTree
{
public:

    BinaryIndexedTree()
    {
    }

    BinaryIndexedTree( const int _N )
    {
        N = _N;
        aib1 = new long long[N + 1];
        aib2 = new long long[N + 1];

        for ( int i = 1; i <= N; ++i )
            aib1[i] = aib2[i] = 0;
    }

    void eraseTree()
    {
        N = 0;

        delete [] aib1;
        delete [] aib2;
    }

    void copiere( const BinaryIndexedTree &T )
    {
        for ( int i = 1; i <= N; ++i )
        {
            this->aib1[i] = T.aib1[i];
            this->aib2[i] = T.aib2[i];
        }
    }

    inline int lsb( int x )
    {
        return x & ( -x );
    }

    void update( long long a[], int p, long long v )
    {
        for ( int i = p; i <= N; i += lsb( i ) )
            a[i] += 1LL * v;
    }

    long long query( long long a[], int p )
    {
        long long s = 0;

        for ( int i = p; i >= 1; i -= lsb( i ) )
            s += 1LL * a[i];

        return s;
    }

    void update( int x, int y, long long v )
    {
        update( aib1, x, +v );
        update( aib1, y + 1, -v );

        update( aib2, x, 1LL * v * ( x - 1 ) );
        update( aib2, y + 1, -1LL * v * ( y ) );
    }

    long long query( int x, int y )
    {
        return query( aib1, y ) * ( y - x + 1 ) - query( aib2, y );
    }

private:

    long long *aib1, *aib2;
    int N;
};
**/
