#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T zero;
    vector<T> value;

    U noop;
    vector<bool> dirty;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _zero = T(), U _noop = U()) {
        zero = _zero, noop = _noop;
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;

        value.resize(2*S, zero);
        dirty.resize(2*S, false);
        prop.resize(2*S, noop);
    }

    void set_leaves(vector<T> &leaves) {
        copy(leaves.begin(), leaves.end(), value.begin() + S);
        fill(value.begin() + S + leaves.size(), value.end(), zero);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) {
            prop[i] = prop[i] + update;
            dirty[i] = true;
        }
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;

            if (dirty[l]) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);

                prop[l] = noop;
                dirty[l] = false;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T res_left = zero, res_right = zero;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) res_left = res_left + value[i++];
            if((j&1) == 0) res_right = value[j--] + res_right;
        }
        return res_left + res_right;
    }
};

const int NPRIME = 3;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }
    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    seg_tree_lazy<node, update> st(N, {0, 0}, {-1});

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, mods(c)});
    st.set_leaves(leaves);

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;
        l--, r--;

        if (t == 1) {
            st.upd(l, r, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T zero;
    vector<T> value;

    U noop;
    vector<bool> dirty;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _zero = T(), U _noop = U()) {
        zero = _zero, noop = _noop;
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;

        value.resize(2*S, zero);
        dirty.resize(2*S, false);
        prop.resize(2*S, noop);
    }

    void set_leaves(vector<T> &leaves) {
        copy(leaves.begin(), leaves.end(), value.begin() + S);
        fill(value.begin() + S + leaves.size(), value.end(), zero);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U &update) {
        value[i] = update(value[i]);
        if(i < S) {
            prop[i] = prop[i] + update;
            dirty[i] = true;
        }
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;

            if (dirty[l]) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);

                prop[l] = noop;
                dirty[l] = false;
            }
        }
    }

    void upd(int i, int j, U &update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T res_left = zero, res_right = zero;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) res_left = res_left + value[i++];
            if((j&1) == 0) res_right = value[j--] + res_right;
        }
        return res_left + res_right;
    }
};

const int NPRIME = 3;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }
    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    seg_tree_lazy<node, update> st(N, {0, 0}, {0, 0}, {-1});

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, mods(c)});
    st.set_leaves(leaves);

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;
        l--, r--;

        if (t == 1) {
            st.upd(l, r, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

static const int NPRIME = 2;
static const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
static const int primes[3] = { P1, P2, P3 };

struct mods {
    ll vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    mods combine(const mods &h, function<ll(ll, ll)> op) {
        mods res;
        for (int i = 0; i < NPRIME; i++)
            res.vals[i] = op(vals[i], h.vals[i]) % primes[i];
        return res;
    }

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }

    mods operator*(const mods &h) { return combine(h, multiplies<ll>()); }
    mods operator+(const mods &h) { return combine(h, plus<ll>()); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        S = _S, def = _def, noop = _noop;
        assert(__builtin_popcount(S) == 1);
        H = 32 - __builtin_clz(S);

        value.resize(2 * S + 1, def);
        prop.resize(2 * S + 1, noop);
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (prop[l] != noop) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    int S = 1; while(S < N) S *= 2;
    seg_tree_lazy<node, update> st(S, {0, 0}, {-1});

    for (int i = 2 * S - 1; i > 0; i--) {
        if(i < S) st.value[i] = st.value[2*i] + st.value[2*i+1];
        else if(i < S + N) st.value[i] = {1, mods(input[i-S])};
        else st.value[i] = {1, mods(0)};
    }

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MOD = 1e9 + 7;
const int BASE = 1009;

const int MAXL = 1e5 + 100;
ll powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = 1ll;
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = (powers[i-1] * BASE) % MOD;
        powsum[i] = (powsum[i-1] + powers[i]) % MOD;
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    void init(int _S) {
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;
        value.resize(2*S, def);
        prop.resize(2*S, noop);
    }

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;
        init(_S);
    }

    seg_tree_lazy<T, U>(vector<T> &leaves, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;

        init(leaves.size());
        copy(leaves.begin(), leaves.end(), value.begin() + S);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    ll hash;

    node operator+(const node &o) {
        return { l + o.l, (hash * powers[o.l] + o.hash) % MOD };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, ll(c)});

    seg_tree_lazy<node, update> st(leaves, {0, 0}, {-1});

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;
        l--, r--;

        if (t == 1) {
            st.upd(l, r, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            ll h1 = st.query(l, r - v).hash;
            ll h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

static const int NPRIME = 1;
static const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
static const int primes[3] = { P1, P2, P3 };

struct mods {
    ll vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    mods combine(const mods &h, function<ll(ll, ll)> op) {
        mods res;
        for (int i = 0; i < NPRIME; i++)
            res.vals[i] = op(vals[i], h.vals[i]) % primes[i];
        return res;
    }

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }

    //mods operator*(const mods &h) { return combine(h, multiplies<ll>()); }
    //mods operator+(const mods &h) { return combine(h, plus<ll>()); }

    mods operator*(const mods &h) {
        mods res;
        for (int i = 0; i < NPRIME; i++)
            res.vals[i] = (vals[i] * h.vals[i]) % primes[i];
        return res;
    }

    mods operator+(const mods &h) {
        mods res;
        for (int i = 0; i < NPRIME; i++)
            res.vals[i] = (vals[i] + h.vals[i]) % primes[i];
        return res;
    }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        S = _S, def = _def, noop = _noop;
        assert(__builtin_popcount(S) == 1);
        H = 32 - __builtin_clz(S);

        value.resize(2 * S + 1, def);
        prop.resize(2 * S + 1, noop);
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (prop[l] != noop) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    int S = 1; while(S < N) S *= 2;
    seg_tree_lazy<node, update> st(S, {0, 0}, {-1});

    for (int i = 2 * S - 1; i > 0; i--) {
        if(i < S) st.value[i] = st.value[2*i] + st.value[2*i+1];
        else if(i < S + N) st.value[i] = {1, mods(input[i-S])};
        else st.value[i] = {1, mods(0)};
    }

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 3;
const int P1 = 1e9 + 7, P2 = 1e9 + 9, P3 = 1e9 + 21;
const int primes[] = {P1, P2, P3};

const int BASE = 1009;
const int MAXL = 1e5 + 100;

struct mods {
    ll vals[3];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    bool operator==(const mods &h) {
        for (int i = 0; i < NPRIME; i++)
            if(vals[i] != h.vals[i])
                return false;
        return true;
    }

    mods operator*(const mods &h) {
        mods res;
        for (int i = 0; i < NPRIME; i++)
            res.vals[i] = (vals[i] * h.vals[i]) % primes[i];
        return res;
    }

    mods operator*(ll m) {
        return (*this) * mods(m);
    }

    mods operator+(const mods &h) {
        mods res;
        for (int i = 0; i < NPRIME; i++)
            res.vals[i] = (vals[i] + h.vals[i]) % primes[i];
        return res;
    }

    mods operator+(ll a) {
        return (*this) + mods(a);
    }
};

mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        S = _S, def = _def, noop = _noop;
        assert(__builtin_popcount(S) == 1);
        H = 32 - __builtin_clz(S);

        value.resize(2 * S + 1, def);
        prop.resize(2 * S + 1, noop);
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (prop[l] != noop) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    int S = 1; while(S < N) S *= 2;
    seg_tree_lazy<node, update> st(S, {0, 0}, {-1});

    for (int i = 2 * S - 1; i > 0; i--) {
        if(i < S) st.value[i] = st.value[2*i] + st.value[2*i+1];
        else if(i < S + N) st.value[i] = {1, mods(input[i-S])};
        else st.value[i] = {1, mods(0)};
    }

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 2;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };
const function<ll(ll, ll)> a = plus<ll>(), m = multiplies<ll>();

struct mods {
    ll vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    mods combine(const mods &h, function<ll(ll, ll)> op) {
        mods res;
        for (int i = 0; i < NPRIME; i++)
            res.vals[i] = op(vals[i], h.vals[i]) % primes[i];
        return res;
    }

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }

    mods operator*(const mods &h) { return combine(h, m); }
    mods operator+(const mods &h) { return combine(h, a); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        S = _S, def = _def, noop = _noop;
        assert(__builtin_popcount(S) == 1);
        H = 32 - __builtin_clz(S);

        value.resize(2 * S + 1, def);
        prop.resize(2 * S + 1, noop);
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (prop[l] != noop) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    int S = 1; while(S < N) S *= 2;
    seg_tree_lazy<node, update> st(S, {0, 0}, {-1});

    for (int i = 2 * S - 1; i > 0; i--) {
        if(i < S) st.value[i] = st.value[2*i] + st.value[2*i+1];
        else if(i < S + N) st.value[i] = {1, mods(input[i-S])};
        else st.value[i] = {1, mods(0)};
    }

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 3;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }
    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    void init(int _S) {
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;
        value.resize(2*S, def);
        prop.resize(2*S, noop);
    }

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;
        init(_S);
    }

    seg_tree_lazy<T, U>(vector<T> &leaves, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;

        init(leaves.size());
        copy(leaves.begin(), leaves.end(), value.begin() + S);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, mods(c)});

    seg_tree_lazy<node, update> st(leaves, {0, 0}, {-1});

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MOD = 1e9 + 9;
const int BASE = 1009;

const int MAXL = 1e5 + 100;
ll powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = 1ll;
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = (powers[i-1] * BASE) % MOD;
        powsum[i] = (powsum[i-1] + powers[i]) % MOD;
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    void init(int _S) {
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;
        value.resize(2*S, def);
        prop.resize(2*S, noop);
    }

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;
        init(_S);
    }

    seg_tree_lazy<T, U>(vector<T> &leaves, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;

        init(leaves.size());
        copy(leaves.begin(), leaves.end(), value.begin() + S);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    ll hash;

    node operator+(const node &o) {
        return { l + o.l, (hash * powers[o.l] + o.hash) % MOD };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, ll(c)});

    seg_tree_lazy<node, update> st(leaves, {0, 0}, {-1});

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;
        l--, r--;

        if (t == 1) {
            st.upd(l, r, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            ll h1 = st.query(l, r - v).hash;
            ll h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

static const int NPRIME = 1;
static const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
static const int primes[3] = { P1, P2, P3 };

struct mods {
    ll vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    mods combine(const mods &h, function<ll(ll, ll)> op) {
        mods res;
        for (int i = 0; i < NPRIME; i++)
            res.vals[i] = op(vals[i], h.vals[i]) % primes[i];
        return res;
    }

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }

    mods operator*(const mods &h) { return combine(h, multiplies<ll>()); }
    mods operator+(const mods &h) { return combine(h, plus<ll>()); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        S = _S, def = _def, noop = _noop;
        assert(__builtin_popcount(S) == 1);
        H = 32 - __builtin_clz(S);

        value.resize(2 * S + 1, def);
        prop.resize(2 * S + 1, noop);
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (prop[l] != noop) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    int S = 1; while(S < N) S *= 2;
    seg_tree_lazy<node, update> st(S, {0, 0}, {-1});

    for (int i = 2 * S - 1; i > 0; i--) {
        if(i < S) st.value[i] = st.value[2*i] + st.value[2*i+1];
        else if(i < S + N) st.value[i] = {1, mods(input[i-S])};
        else st.value[i] = {1, mods(0)};
    }

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 2;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }

    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        S = _S, def = _def, noop = _noop;
        assert(__builtin_popcount(S) == 1);
        H = 32 - __builtin_clz(S);

        value.resize(2 * S + 1, def);
        prop.resize(2 * S + 1, noop);
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (prop[l] != noop) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    int S = 1; while(S < N) S *= 2;
    seg_tree_lazy<node, update> st(S, {0, 0}, {-1});

    for (int i = 2 * S - 1; i > 0; i--) {
        if(i < S) st.value[i] = st.value[2*i] + st.value[2*i+1];
        else if(i < S + N) st.value[i] = {1, mods(input[i-S])};
        else st.value[i] = {1, mods(0)};
    }

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 2;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }
    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    void init(int _S) {
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;
        value.resize(2*S, def);
        prop.resize(2*S, noop);
    }

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;
        init(_S);
    }

    seg_tree_lazy<T, U>(vector<T> &leaves, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;

        init(leaves.size());
        copy(leaves.begin(), leaves.end(), value.begin() + S);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            value[l] = value[2*l] + value[2*l+1];
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, mods(c)});

    seg_tree_lazy<node, update> st(leaves, {0, 0}, {-1});

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 3;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }
    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    void init(int _S) {
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;
        value.resize(2*S, def);
        prop.resize(2*S, noop);
    }

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;
        init(_S);
    }

    seg_tree_lazy<T, U>(vector<T> &leaves, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;

        init(leaves.size());
        copy(leaves.begin(), leaves.end(), value.begin() + S);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, mods(c)});

    seg_tree_lazy<node, update> st(leaves, {0, 0}, {-1});

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;
        l--, r--;

        if (t == 1) {
            st.upd(l, r, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MOD = 1e9 + 273;
const int BASE = 1009;

const int MAXL = 1e5 + 100;
ll powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = 1ll;
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = (powers[i-1] * BASE) % MOD;
        powsum[i] = (powsum[i-1] + powers[i]) % MOD;
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    void init(int _S) {
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;
        value.resize(2*S, def);
        prop.resize(2*S, noop);
    }

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;
        init(_S);
    }

    seg_tree_lazy<T, U>(vector<T> &leaves, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;

        init(leaves.size());
        copy(leaves.begin(), leaves.end(), value.begin() + S);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    ll hash;

    node operator+(const node &o) {
        return { l + o.l, (hash * powers[o.l] + o.hash) % MOD };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, ll(c)});

    seg_tree_lazy<node, update> st(leaves, {0, 0}, {-1});

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;
        l--, r--;

        if (t == 1) {
            st.upd(l, r, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            ll h1 = st.query(l, r - v).hash;
            ll h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 2;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }
    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    void init(int _S) {
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;
        value.resize(2*S, def);
        prop.resize(2*S, noop);
    }

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;
        init(_S);
    }

    seg_tree_lazy<T, U>(vector<T> &leaves, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;

        init(leaves.size());
        copy(leaves.begin(), leaves.end(), value.begin() + S);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            value[i] = value[2*l] + value[2*l+1];
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, mods(c)});

    seg_tree_lazy<node, update> st(leaves, {0, 0}, {-1});

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 2;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }
    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    void init(int _S) {
        for (S = 1, H = 1; S < _S; ) S *= 2, H++;
        value.resize(2*S, def);
        prop.resize(2*S, noop);
    }

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;
        init(_S);
    }

    seg_tree_lazy<T, U>(vector<T> &leaves, T _def = T(), U _noop = U()) {
        def = _def, noop = _noop;

        init(leaves.size());
        copy(leaves.begin(), leaves.end(), value.begin() + S);

        for (int i = S - 1; i > 0; i--)
            value[i] = value[2 * i] + value[2 * i + 1];
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    vector<node> leaves;
    for (char c : input)
        leaves.push_back({1, mods(c)});

    seg_tree_lazy<node, update> st(leaves, {0, 0}, {-1});

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int NPRIME = 2;
const int P1 = 1e9+7, P2 = 1e9+9, P3 = 1e9+21;
const int primes[3] = { P1, P2, P3 };

struct mods {
    int vals[NPRIME];

    mods(ll value = 0) {
        for (int i = 0; i < NPRIME; i++)
            vals[i] = value % primes[i];
    }

    #define combine(h, op) \
        mods res; \
        for (int i = 0; i < NPRIME; i++) \
            res.vals[i] = (vals[i] op h.vals[i]) % primes[i]; \
        return res;

    bool operator==(const mods &h) { return !memcmp(this, &h, sizeof(mods)); }
    mods operator*(const mods &h) { combine(h, * 1ll *); }
    mods operator+(const mods &h) { combine(h, +); }

    mods operator*(ll m) { return (*this) * mods(m); }
    mods operator+(ll a) { return (*this) + mods(a); }
};

const int BASE = 1009;
const int MAXL = 1e5 + 100;
mods powers[MAXL], powsum[MAXL];

void init() {
    powers[0] = mods(1);
    powsum[0] = powers[0];

    for(int i=1; i<MAXL; i++) {
        powers[i] = powers[i-1] * BASE;
        powsum[i] = powsum[i-1] + powers[i];
    }
}

template<typename T, typename U> struct seg_tree_lazy {
    int S, H;

    T def;
    vector<T> value;

    U noop;
    vector<U> prop;

    seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) {
        S = _S, def = _def, noop = _noop;
        assert(__builtin_popcount(S) == 1);
        H = 32 - __builtin_clz(S);

        value.resize(2 * S + 1, def);
        prop.resize(2 * S + 1, noop);
    }

    void apply(int i, U update) {
        value[i] = update(value[i]);
        if(i < S) prop[i] = prop[i] + update;
    }

    void rebuild(int i) {
        for (int l = i/2; l; l /= 2) {
            T combined = value[2*l] + value[2*l+1];
            value[l] = prop[l](combined);
        }
    }

    void propagate(int i) {
        for (int h = H; h > 0; h--) {
            int l = i >> h;
            if (memcmp(&prop[l], &noop, sizeof(U))) {
                apply(2*l, prop[l]);
                apply(2*l+1, prop[l]);
                prop[l] = noop;
            }
        }
    }

    void upd(int i, int j, U update) {
        i += S, j += S;
        propagate(i), propagate(j);

        for (int l = i, r = j; l <= r; l /= 2, r /= 2) {
            if((l&1) == 1) apply(l++, update);
            if((r&1) == 0) apply(r--, update);
        }

        rebuild(i), rebuild(j);
    }

    T query(int i, int j){
        i += S, j += S;
        propagate(i), propagate(j);

        T resl = def, resr = def;
        for(; i <= j; i /= 2, j /= 2){
            if((i&1) == 1) resl = resl + value[i++];
            if((j&1) == 0) resr = value[j--] + resr;
        }
        return resl + resr;
    }
};

struct node {
    int l;
    mods hash;

    node operator+(const node &o) {
        return { l + o.l, hash * powers[o.l] + o.hash };
    }
};

struct update {
    int v;

    node operator()(node &n) {
        if (v == -1) return n;
        return { n.l, powsum[n.l-1] * v };
    }

    update operator+(const update &o) {
        return o;
    }

    bool operator!=(const update &o) {
        return v != o.v;
    }
};

int N, M, K;
string input;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0), cout.tie(0), cout.precision(15);

    init();

    cin >> N >> M >> K;
    cin >> input;

    int S = 1; while(S < N) S *= 2;
    seg_tree_lazy<node, update> st(S, {0, 0}, {-1});

    for (int i = 2 * S - 1; i > 0; i--) {
        if(i < S) st.value[i] = st.value[2*i] + st.value[2*i+1];
        else if(i < S + N) st.value[i] = {1, mods(input[i-S])};
        else st.value[i] = {1, mods(0)};
    }

    for (int q = 0; q < M + K; q++) {
        int t, l, r, v;
        cin >> t >> l >> r >> v;

        if (t == 1) {
            st.upd(l - 1, r - 1, { '0' + v });
        } else {
            if (l > r - v) {
                cout << "YES\n";
                continue;
            }

            l--, r--;
            mods h1 = st.query(l, r - v).hash;
            mods h2 = st.query(l + v, r).hash;

            if (h1 == h2) cout << "YES\n";
            else cout << "NO\n";
        }
    }
}


#include <bits/stdc++.h>
#define MOD 666013
#define Nmax 500005
#define pb push_back
#define mp make_pair
#define X 10
#define INF 2000000000
#define eps 0.000000000001

using namespace std;

int n,a[Nmax],l[Nmax],r[Nmax],x[Nmax],specific[Nmax],tip[Nmax],ans[Nmax];
char sir[Nmax];

int aint[3*Nmax],lazy[3*Nmax],p[Nmax],s[Nmax];

struct el
{
    int val,ind;
};
vector <el> S[Nmax];

inline void Pr(int nod, int st, int dr)
{
    if(lazy[nod]==-1) return;
    int mij=((st+dr)>>1);
    aint[2*nod]=(1LL*lazy[nod]*s[mij-st])%MOD;
    aint[2*nod+1]=(1LL*lazy[nod]*s[dr-mij-1])%MOD;
    lazy[2*nod]=lazy[2*nod+1]=lazy[nod]; lazy[nod]=-1;
}

inline void Upd(int nod, int st, int dr, int x, int y, int val)
{
    if(st==x && y==dr)
    {
        aint[nod]=(1LL*s[dr-st]*val)%MOD; lazy[nod]=val; return;
    }
    Pr(nod,st,dr);
    int mij=((st+dr)>>1);
    if(y<=mij)
    {
        Upd(2*nod,st,mij,x,y,val);
    }
    else
        if(x>mij)
            Upd(2*nod+1,mij+1,dr,x,y,val);
        else
        {
            Upd(2*nod,st,mij,x,mij,val);
            Upd(2*nod+1,mij+1,dr,mij+1,y,val);
        }
    aint[nod]=(1LL*aint[2*nod]*p[dr-mij] + aint[2*nod+1]) %MOD;
}

inline int Qry(int nod, int st, int dr, int x, int y)
{
    if(st==x && y==dr)
        return aint[nod];
    Pr(nod,st,dr);
    int mij=((st+dr)>>1);
    if(y<=mij)
    {
        return Qry(2*nod,st,mij,x,y);
    }
    else
        if(x>mij)
            return Qry(2*nod+1,mij+1,dr,x,y);
        else
        {
            return (1LL * Qry(2*nod,st,mij,x,mij) * p[y-mij] + Qry(2*nod+1,mij+1,dr,mij+1,y))%MOD;
        }
}

inline void Fix(int &x)
{
    if(x>=MOD) x-=MOD;
}

int main()
{
    int i,j,m,k;
    el w;
    #ifndef ONLINE_JUDGE
        freopen ("date.in","r",stdin);
        freopen ("date.out","w",stdout);
    #endif
    cin.sync_with_stdio(0);
    cin>>n>>m>>k;
    for(i=0;i<3*Nmax;++i) lazy[i]=-1;
    p[0]=1;
    for(i=1;i<=n;++i) p[i]=(1LL*p[i-1]*X)%MOD;
    s[0]=1;
    for(i=1;i<=n;++i) s[i]=(s[i-1] + p[i])%MOD;
    m+=k;
    cin>>(sir+1);
    for(i=1;i<=n;++i)
    {
        a[i]=sir[i]-'0';
        Upd(1,1,n,i,i,a[i]);
    }
    for(i=1;i<=m;++i)
    {
        cin>>tip[i]>>l[i]>>r[i]>>x[i];
        if(tip[i]==2)
        {
            w.val=x[i]; w.ind=i;
            S[(r[i]-l[i]+1)-(r[i]-l[i]+1)%x[i] - x[i]].pb(w);
        }
    }

    for(i=0;i<=n;++i)
    {
        if(i==0)
        {
            for(j=1;j<=n;++j)
            {
                ++ans[j];
                Fix(ans[j]);
            }
        }
        else
        {
            for(j=1;j*j<=i;++j)
                if(i%j==0)
                {
                    ans[j]+=p[i]; Fix(ans[j]);
                    if(j*j!=i)
                    {
                        ans[i/j]+=p[i];
                        Fix(ans[i/j]);
                    }
                }
        }
        //cout<<ans[3]<<"\n";
        for(auto it : S[i]) specific[it.ind]=ans[it.val];
    }

    for(i=1;i<=m;++i)
    {
        if(tip[i]==1)
            Upd(1,1,n,l[i],r[i],x[i]);
        else
        {
                int val=Qry(1,1,n,l[i],l[i]+x[i]-1),aux;
                aux = (1LL * val * specific[i])%MOD;
                if((r[i]-l[i]+1)%x[i]) aux=(1LL*aux * p[(r[i]-l[i]+1)%x[i]] + Qry(1,1,n,r[i]-(r[i]-l[i]+1)%x[i]+1,r[i]));
                if(aux == Qry(1,1,n,l[i],r[i])) cout<<"YES\n";
                else cout<<"NO\n";
        }
    }
    //cout<<specific[3];
    return 0;
}


#include <bits/stdc++.h>
#define MOD 454287423
#define Nmax 200005
#define pb push_back
#define mp make_pair
#define X 153
#define INF 2000000000
#define eps 0.000000000001

using namespace std;

int n,a[Nmax],l[Nmax],r[Nmax],x[Nmax],specific[Nmax],tip[Nmax],ans[Nmax];
char sir[Nmax];

int aint[3*Nmax],lazy[3*Nmax],p[Nmax],s[Nmax];

struct el
{
    int val,ind;
};
vector <el> S[Nmax];

inline void Pr(int nod, int st, int dr)
{
    if(!lazy[nod]) return;
    int mij=((st+dr)>>1);
    aint[2*nod]=(1LL*lazy[nod]*s[mij-st])%MOD;
    aint[2*nod+1]=(1LL*lazy[nod]*s[dr-mij-1])%MOD;
    lazy[2*nod]=lazy[2*nod+1]=lazy[nod]; lazy[nod]=0;
}

inline void Upd(int nod, int st, int dr, int x, int y, int val)
{
    if(st==x && y==dr)
    {
        aint[nod]=(1LL*s[dr-st]*val)%MOD; lazy[nod]=val; return;
    }
    Pr(nod,st,dr);
    int mij=((st+dr)>>1);
    if(y<=mij)
    {
        Upd(2*nod,st,mij,x,y,val);
    }
    else
        if(x>mij)
            Upd(2*nod+1,mij+1,dr,x,y,val);
        else
        {
            Upd(2*nod,st,mij,x,mij,val);
            Upd(2*nod+1,mij+1,dr,mij+1,y,val);
        }
    aint[nod]=(1LL*aint[2*nod]*p[dr-mij] + aint[2*nod+1]) %MOD;
}

inline int Qry(int nod, int st, int dr, int x, int y)
{
    if(st==x && y==dr)
        return aint[nod];
    Pr(nod,st,dr);
    int mij=((st+dr)>>1);
    if(y<=mij)
    {
        return Qry(2*nod,st,mij,x,y);
    }
    else
        if(x>mij)
            return Qry(2*nod+1,mij+1,dr,x,y);
        else
        {
            return (1LL * Qry(2*nod,st,mij,x,mij) * p[y-mij] + Qry(2*nod+1,mij+1,dr,mij+1,y))%MOD;
        }
}

inline void Fix(int &x)
{
    if(x>=MOD) x-=MOD;
}

int main()
{
    int i,j,m,k;
    el w;
    #ifndef ONLINE_JUDGE
        freopen ("date.in","r",stdin);
        freopen ("date.out","w",stdout);
    #endif
    cin.sync_with_stdio(0);
    cin>>n>>m>>k;
    p[0]=1;
    for(i=1;i<=n;++i) p[i]=(1LL*p[i-1]*X)%MOD;
    s[0]=1;
    for(i=1;i<=n;++i) s[i]=(s[i-1] + p[i])%MOD;
    m+=k;
    cin>>(sir+1);
    for(i=1;i<=n;++i)
    {
        a[i]=sir[i]-'0';
        Upd(1,1,n,i,i,a[i]);
    }
    for(i=1;i<=m;++i)
    {
        cin>>tip[i]>>l[i]>>r[i]>>x[i];
        if(tip[i]==2 && (r[i]-l[i]+1)%x[i]==0)
        {
            w.val=x[i]; w.ind=i;
            S[r[i]-l[i]+1-x[i]].pb(w);
        }
    }

    for(i=0;i<=n;++i)
    {
        if(i==0)
        {
            for(j=1;j<=n;++j)
            {
                ++ans[j];
                Fix(ans[j]);
            }
        }
        else
        {
            for(j=1;j*j<=i;++j)
                if(i%j==0)
                {
                    ans[j]+=p[i]; Fix(ans[j]);
                    if(j*j!=i)
                    {
                        ans[i/j]+=p[i];
                        Fix(ans[i/j]);
                    }
                }
        }
        //cout<<ans[3]<<"\n";
        for(auto it : S[i]) specific[it.ind]=ans[it.val];
    }

    for(i=1;i<=m;++i)
    {
        if(tip[i]==1)
            Upd(1,1,n,l[i],r[i],x[i]);
        else
        {
            if((r[i]-l[i]+1)%x[i]) cout<<"NO\n";
            else
            {
                int val=Qry(1,1,n,l[i],l[i]+x[i]-1);
                if((1LL * val * specific[i])%MOD == Qry(1,1,n,l[i],r[i])) cout<<"YES\n";
                else cout<<"NO\n";
            }
        }
    }
    //cout<<specific[3];
    return 0;
}


#Code by Sounak, IIESTS
#------------------------------warmup----------------------------

import os
import sys
import math
from io import BytesIO, IOBase
from fractions import Fraction
import collections
from itertools import permutations
from collections import defaultdict

BUFSIZE = 8192

class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = "x" in file.mode or "r" not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b"\n") + (not b)
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            self.buffer.truncate(0), self.buffer.seek(0)

class IOWrapper(IOBase):
    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode("ascii"))
        self.read = lambda: self.buffer.read().decode("ascii")
        self.readline = lambda: self.buffer.readline().decode("ascii")

sys.stdin, sys.stdout = IOWrapper(sys.stdin), IOWrapper(sys.stdout)
input = lambda: sys.stdin.readline().rstrip("\r\n")

#-------------------game starts now-----------------------------------------------------
n,m,k=map(int,input().split())
g=math.gcd(n*m,k)
d=(n*m)//g
k//=g
#print(d,k)
if d%k!=0 and k!=2:
    print("NO")
else:
    num=(2*d)//k
    j=1
    for i in range (2,int(math.sqrt(num))+1):
        if num%i==0:
            j=i
    l=num//j
    #print(j,l)
    if j<=n and l<=m:
        print("YES")
        print("0 0")
        print(0,l)
        print(j,0)
    elif j<=m and l<=n:
        print("YES")
        print("0 0")
        print(0,j)
        print(l,0)
    else:
        print("NO")


#Code by Sounak, IIESTS
#------------------------------warmup----------------------------

import os
import sys
import math
from io import BytesIO, IOBase
from fractions import Fraction
import collections
from itertools import permutations
from collections import defaultdict

BUFSIZE = 8192

class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = "x" in file.mode or "r" not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b"\n") + (not b)
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            self.buffer.truncate(0), self.buffer.seek(0)

class IOWrapper(IOBase):
    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode("ascii"))
        self.read = lambda: self.buffer.read().decode("ascii")
        self.readline = lambda: self.buffer.readline().decode("ascii")

sys.stdin, sys.stdout = IOWrapper(sys.stdin), IOWrapper(sys.stdout)
input = lambda: sys.stdin.readline().rstrip("\r\n")

#-------------------game starts now-----------------------------------------------------
n,m,k=map(int,input().split())
g=math.gcd(n*m,k)
d=(n*m)//g
f=k//g
#print(d,f)
if d%f!=0 and f!=2:
    print("NO")
else:
    j=1
    l=1
    copy1,copy2=n,m
    ch=1
    if k%2==0:
        k//=2
        ch=0
    while k%2==0:
        k//=2
        if n%2==0:
            n//=2
        else:
            m//=2
    for i in range (3,int(math.sqrt(k))+1,2):
        while k%i==0:
            k//=i
            if n%i==0:
                n//=i
            else:
                m//=i
    if k>2:
        if n%k==0:
            n//=k
        else:
            m//=k
    if ch==1:
        if n*2<=copy1:
            n*=2
        else:
            m*=2
    print("YES")
    print("0 0")
    print(0,m)
    print(n,0)


def gcd(a,b):
    if a%b==0:
        return b
    else:
        return gcd(b,a%b)

n,m,k=list(map(int,input().split()))
u,v=n,m
a=n*m*2
if a%k==0:
    print("NO")
else:
    print("YES")
    if k%2==0:
        k=k//2
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        print(0,0)
        print(0,m)
        print(n,0)
    else:
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        print(n,m,k,c)
        if u<2*n:
            m=2*m
            print(0,0)
            print(0,m)
            print(n,0)
        else:
            n=2*n
            print(0,0)
            print(0,m)
            print(n,0)


def gcd(a,b):
    if a%b==0:
        return b
    else:
        return gcd(b,a%b)

n,m,k=list(map(int,input().split()))
u,v=n,m
a=((n*m*2)/k)
if a!=int(a):
    print("NO")
else:
    print("YES")
    if k%2==0:
        k=k//2
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        print(0,0)
        print(0,m)
        print(n,0)
    else:
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        if u<2*n:
            m=2*m
            print(0,0)
            print(0,m)
            print(n,0)
        else:
            n=2*n
            print(0,0)
            print(0,m)
            print(n,0)


def gcd(a,b):
    if a%b==0:
        return b
    else:
        return gcd(b,a%b)

n,m,k=list(map(int,input().split()))
u,v=n,m
a=n*m*2
if a%k!=0:
    print("NO")
else:
    print("YES")
    if k%2==0:
        k=k//2
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        print(0,0)
        print(0,m)
        print(n,0)
    else:
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        if u<2*n:
            m=2*m
            print(0,0)
            print(0,m)
            print(n,0)
        else:
            n=2*n
            print(0,0)
            print(0,m)
            print(n,0)


def gcd(a,b):
    if a%b==0:
        return b
    else:
        return gcd(b,a%b)

n,m,k=list(map(int,input().split()))
u,v=n,m
a=((n*m*2)/k)
if a!=int(a):
    print("NO")
else:
    print("YES")
    if k%2==0:
        k=k//2
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        print(0,0)
        print(0,m)
        print(n,0)
    else:
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        if u<2*n:
            m=2*m
            print(0,0)
            print(0,m)
            print(n,0)
        else:
            print(0,0)
            print(0,m)
            print(n,0)


def gcd(a,b):
    if a%b==0:
        return b
    else:
        return gcd(b,a%b)

n,m,k=list(map(int,input().split()))
u,v=n,m
a=((n*m*2)/k)
if a!=int(a):
    print("NO")
else:
    if k%2==0:
        k=k//2
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        print(0,0)
        print(0,m)
        print(n,0)
    else:
        c=gcd(n,k)
        k=k//c
        n=n//c
        m=m//k
        if u<2*n:
            m=2*m
            print(0,0)
            print(0,m)
            print(n,0)
        else:
            print(0,0)
            print(0,m)
            print(n,0)


import sys
import math
n,m,k=map(int,sys.stdin.readline().split())
bh=n*m*2/k
if bh%1!=0:
    print('NO')
    sys.exit()
if k%2==0:
    g=math.gcd(k//2,n)
    a=n//g
    b=m//(k//g)
else:
    g=math.gcd(k,n)
    a=n//g
    if 2*a<=n:
        a=2*a
        b=m//(k//g)
    else:
        b=2*m//(k//g)

print('YES')
print(0,0)
print(a,0)
print(0,b)


import sys
import math
def get(bh,n,m):
    for i in range(1,int(math.sqrt(bh))+1):
        if bh%i==0:
            x=bh//i
            if 0<=x<=n and 0<=i<=m:
                return (x,i)
            if 0<=i<=n and 0<=x<=m:
                return (i,x)
    return (-1,-1)
n,m,k=map(int,sys.stdin.readline().split())
bh=n*m*2/k
if bh%1!=0:
    print('NO')
    sys.exit()
x,y=get(bh,n,m)
if x==-1 and y==-1:
    print('NO')
    sys.exit()
print('YES')
print(0,0)
print(int(x),0)
print(1,int(y))


import sys
import math
n,m,k=map(int,sys.stdin.readline().split())
bh=n*m*2/k
if bh%1!=0:
    print('NO')
    sys.exit()
if k%2==0:
    g=math.gcd(k//2,n)
    a=n//g
    b=m//(k//(2*g))
else:
    g=math.gcd(k,n)
    a=n//g
    if 2*a<=n:
        a=2*a
        b=m//(k//g)
    else:
        b=2*m//(k//g)

print('YES')
print(0,0)
print(a,0)
print(0,b)


import sys
import math
n,m,k=map(int,sys.stdin.readline().split())
bh=n*m*2/k
#print(int(bh),'bh')
if bh%1!=0:
    print('NO')
    sys.exit()
if k%2==0:
    g=math.gcd(k//2,n)
    a=n//g
    if m%(k//(2*g))!=0:
        print('NO')
        sys.exit()
    b=m//(k//(2*g))
else:
    g=math.gcd(k,n)
    #print(g,'g')
    a=n//g
    z=k//g
    if m%z!=0:
        print('NO')
        sys.exit()
    b=m//(k//g)
    if 2*a<=n:
        a=2*a
        #b=m//(k//g)
    else:
        b=2*b

print('YES')
print(0,0)
print(a,0)
print(0,b)


def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

n, m, k = map(int, input().split())
if n * m * 2 % k != 0:
    print('NO')
else:
    #print('YES')
    s2 = n * m * 2 // k
    ans = [(0, 0)]

    """i = 1
    while i * i <= s2:
        if s2 % i == 0:
            if i <= n and s2 // i <= m:
                ans.append((i, 0))
                ans.append((0, s2 // i))
                break
            if s2 // i <= n and i <= m:
                ans.append((s2 // i, 0))
                ans.append((0, i))
                break
        i += 1
    if ans == [(0, 0)]:
        print('NO')
    else:
        print('YES')
        for i in ans:
            print(i[0], i[1])"""

    xx1 = n // gcd(n, k)
    yy1 = s2 // xx1

    yy2 = m // gcd(m, k)
    xx2 = s2 // yy2
    if xx1 <= n and yy1 <= m:
        print('YES')
        print(0, 0)
        print(xx1, 0)
        print(0, yy1)
    elif xx2 <= n and yy2 <= m:
        print('YES')
        print(0, 0)
        print(xx2, 0)
        print(0, yy2)
    else:
        print('NO')


def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

n, m, k = map(int, input().split())
if n * m * 2 % k != 0:
    print('NO')
else:
    #print('YES')
    s2 = n * m * 2 // k
    ans = [(0, 0)]

    """i = 1
    while i * i <= s2:
        if s2 % i == 0:
            if i <= n and s2 // i <= m:
                ans.append((i, 0))
                ans.append((0, s2 // i))
                break
            if s2 // i <= n and i <= m:
                ans.append((s2 // i, 0))
                ans.append((0, i))
                break
        i += 1
    if ans == [(0, 0)]:
        print('NO')
    else:
        print('YES')
        for i in ans:
            print(i[0], i[1])"""

    xx1 = max(n // gcd(n, k), gcd(n, k))
    yy1 = s2 // xx1

    yy2 = max(m // gcd(m, k), gcd(m, k))
    xx2 = s2 // yy2
    if xx1 <= n and yy1 <= m:
        print('YES')
        print(0, 0)
        print(xx1, 0)
        print(0, yy1)
    elif xx2 <= n and yy2 <= m:
        print('YES')
        print(0, 0)
        print(xx2, 0)
        print(0, yy2)
    else:
        print('NO')


def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

n, m, k = map(int, input().split())
if n * m * 2 % k != 0:
    print('NO')
else:
    #print('YES')
    s2 = n * m * 2 // k
    ans = [(0, 0)]

    """i = 1
    while i * i <= s2:
        if s2 % i == 0:
            if i <= n and s2 // i <= m:
                ans.append((i, 0))
                ans.append((0, s2 // i))
                break
            if s2 // i <= n and i <= m:
                ans.append((s2 // i, 0))
                ans.append((0, i))
                break
        i += 1
    if ans == [(0, 0)]:
        print('NO')
    else:
        print('YES')
        for i in ans:
            print(i[0], i[1])"""

    xx1 = n // gcd(n, k)
    if gcd(n, k) == n:
        xx1 = n
    yy1 = s2 // xx1

    yy2 = m // gcd(m, k)
    if gcd(m, k) == m:
        yy2 = m
    xx2 = s2 // yy2
    if xx1 <= n and yy1 <= m:
        print('YES')
        print(0, 0)
        print(xx1, 0)
        print(0, yy1)
    elif xx2 <= n and yy2 <= m:
        print('YES')
        print(0, 0)
        print(xx2, 0)
        print(0, yy2)
    else:
        print('NO')


def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

n, m, k = map(int, input().split())
if n * m * 2 % k != 0:
    print('NO')
else:
    #print('YES')
    s2 = n * m * 2 // k
    ans = [(0, 0)]

    """i = 1
    while i * i <= s2:
        if s2 % i == 0:
            if i <= n and s2 // i <= m:
                ans.append((i, 0))
                ans.append((0, s2 // i))
                break
            if s2 // i <= n and i <= m:
                ans.append((s2 // i, 0))
                ans.append((0, i))
                break
        i += 1
    if ans == [(0, 0)]:
        print('NO')
    else:
        print('YES')
        for i in ans:
            print(i[0], i[1])"""

    xx1 = n // gcd(n, k)
    yy1 = s2 // xx1

    yy2 = m // gcd(m, k)
    xx2 = s2 // yy2

    if s2 % n == 0:
        print('YES')
        print(0, 0)
        print(n, 0)
        print(0, s2 // n)
    elif s2 % m == 0:
        print('YES')
        print(0, 0)
        print(s2 // m, 0)
        print(0, m)
    elif xx1 <= n and yy1 <= m and xx1 * yy1 == n * m * 2 // k:
        print('YES')
        print(0, 0)
        print(xx1, 0)
        print(0, yy1)
    elif xx2 <= n and yy2 <= m and xx2 * yy2 == n * m * 2 // k:
        print('YES')
        print(0, 0)
        print(xx2, 0)
        print(0, yy2)
    else:
        print('NO')


def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

n, m, k = map(int, input().split())
if n * m * 2 % k != 0:
    print('NO')
else:
    #print('YES')
    s2 = n * m * 2 // k
    ans = [(0, 0)]

    """i = 1
    while i * i <= s2:
        if s2 % i == 0:
            if i <= n and s2 // i <= m:
                ans.append((i, 0))
                ans.append((0, s2 // i))
                break
            if s2 // i <= n and i <= m:
                ans.append((s2 // i, 0))
                ans.append((0, i))
                break
        i += 1
    if ans == [(0, 0)]:
        print('NO')
    else:
        print('YES')
        for i in ans:
            print(i[0], i[1])"""

    n = n // gcd(n, k)
    m = s2 // n
    print('YES')
    print(0, 0)
    print(n, 0)
    print(0, m)


def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

n, m, k = map(int, input().split())
if n * m * 2 % k != 0:
    print('NO')
else:
    #print('YES')
    s2 = n * m * 2 // k
    ans = [(0, 0)]

    """i = 1
    while i * i <= s2:
        if s2 % i == 0:
            if i <= n and s2 // i <= m:
                ans.append((i, 0))
                ans.append((0, s2 // i))
                break
            if s2 // i <= n and i <= m:
                ans.append((s2 // i, 0))
                ans.append((0, i))
                break
        i += 1
    if ans == [(0, 0)]:
        print('NO')
    else:
        print('YES')
        for i in ans:
            print(i[0], i[1])"""

    xx1 = n // gcd(n, k)
    yy1 = s2 // xx1

    yy2 = m // gcd(m, k)
    xx2 = s2 // yy2
    if xx1 <= n and yy1 <= m:
        print('YES')
        print(0, 0)
        print(xx1, 0)
        print(0, yy1)
    elif xx2 <= n and yy2 <= m:
        print('YES')
        print(0, 0)
        print(xx2, 0)
        print(0, yy2)
    else:
        print(0 // 0)


from sys import stdin, stdout
input = stdin.buffer.readline
#print = stdout.write

n, m, k = map(int, input().split())
if 2 * n * m % k == 0:
	i = 2
	t = k
	N = n
	while i * i <= k:
		while t % i == 0 and (n % i == 0 or m % i == 0):
			t //= i
			if n % i == 0:
				n //= i
			else:
				m //= i
		i += 1
	if t % 2:
		if t > 1:
			if n % t == 0:
				n //= t
			else:
				m //= t
		if n * 2 <= N:
			n *= 2
		else:
			m *= 2
	else:
		t //= 2
		if t > 1:
			if n % t == 0:
				n //= t
			else:
				m //= t

	print('YES')
	print(0, 0)
	print(n, 0)
	print(0, m)
else:
	print('NO')


from sys import stdin, stdout
input = stdin.buffer.readline
#print = stdout.write

n, m, k = map(int, input().split())
if 2 * n * m % k == 0:
	i = 2
	t = k
	while i * i <= k:
		while t % i == 0 and (n % i ==0 or m % i == 0):
			t //= i
			if n % i == 0:
				n //= i
			else:
				m //= i
	print(n, m, t)
	if t % 2:
		if t > 1:
			if n % t == 0:
				n //= t
			else:
				m //= t
		if n < m:
			n *= 2
		else:
			m *= 2
	else:
		t //= 2
		if t > 1:
			if n % t == 0:
				n //= t
			else:
				m //= t

	print('YES')
	print(0, 0)
	print(n, 0)
	print(0, m)
else:
	print('NO')


from sys import stdin, stdout
input = stdin.buffer.readline
#print = stdout.write

n, m, k = map(int, input().split())
if 2 * n * m % k == 0:
	i = 2
	t = k
	while i * i <= k:
		while t % i == 0 and (n % i ==0 or m % i == 0):
			t //= i
			if n % i == 0:
				n //= i
			else:
				m //= i
		i += 1
	if t % 2:
		if t > 1:
			if n % t == 0:
				n //= t
			else:
				m //= t
		if n < m:
			n *= 2
		else:
			m *= 2
	else:
		t //= 2
		if t > 1:
			if n % t == 0:
				n //= t
			else:
				m //= t

	print('YES')
	print(0, 0)
	print(n, 0)
	print(0, m)
else:
	print('NO')


from sys import stdin, stdout
input = stdin.buffer.readline
#print = stdout.write

n, m, k = map(int, input().split())
if 2 * n * m % k == 0:
	i = 2
	t = k
	while i * i <= k:
		while t % i == 0 and (n % i ==0 or m % i == 0):
			t //= i
			if n % i == 0:
				n //= i
			else:
				m //= i
	if t % 2:
		if t > 1:
			if n % t == 0:
				n //= t
			else:
				m //= t
		if n < m:
			n *= 2
		else:
			m *= 2
	else:
		t //= 2
		if t > 1:
			if n % t == 0:
				n //= t
			else:
				m //= t

	print('YES')
	print(0, 0)
	print(n, 0)
	print(0, m)
else:
	print('NO')


from sys import stdin, stdout
input = stdin.buffer.readline
#print = stdout.write

n, m, k = map(int, input().split())
if 2 * n * m % k == 0:
	print('YES')
	print(0, 0)
	print(1, 0)
	print(0, 2 * n * m // k)
else:
	print('NO')


n,m,k = map(int,input().split())
area = (n*m)/k
if(area != int(area)):
    print("NO")
else:
    if(2*m)%k==0 and (2*m)//k<=m:
        print("YES")
        print("0 0")
        print(n,"0")
        print("0",2*m//k)
    elif(2*n)%k==0 and (2*n)//k<=n:
        print("YES")
        print("0 0")
        print(2*n//k,"0")
        print("0",m)
    else:
        print("NO")


n,m,k = map(int,input().split())
area = (n*m)/k
if(area != int(area)):
    print("NO")
else:
    print("YES")
    print("0",int(2*m/k))
    print(n,"0")
    print("0 0")


n,m,k = map(int,input().split())
area = (n*m)/k
if(area != int(area)):
    print("NO")
else:
    print("YES")
    print(2,"0")
    print("0",int(area))
    print("0 0")


n,m,k = map(int,input().split())
area = (n*m)/k
if(area != int(area)):
    print("NO")
else:
    print("YES")
    print("0",m)
    print(int(2*n/k),"0")
    print("0 0")


n,m,k = map(int,input().split())
area = (n*m)/k
if(area != int(area)):
    print("NO")
else:
    if(2*m)%k==0 and (2*m)//k<=m:
        print("YES")
        print("0 0")
        print(n,"0")
        print("0",2*m//k)
    elif(2*n)%k==0 and (2*n)//k<=n:
        print("YES")
        print("0 0")
        print(2*n//k,"0")
        print("0",m)
    elif(n*m//k<=n and m>=2):
        print("YES")
        print("0 0")
        print("0 2")
        print(n*m//k,"0")
    elif(n*m//k<=m and n>=2):
        print("YES")
        print("0 0")
        print("2 0")
        print("0",n*m//k)
    else:
        print("NO")


def gcd(a,b):
    if(a==0):
        return b
    return gcd(b%a,a)

n,m,k = map(int,input().split())
area = (n*m)/k
flag = 0
if(k%2==0):
    flag = k%2
    k=k//2
if(n*m)%k!=0:
    print("NO")
else:
    s = gcd(n,k)
    k = k//s
    a = n//s
    s = gcd(m,k)
    k = k//s
    assert(k == 1)
    b = m//s
    if(not (flag & 1)):
        if(a<n):
            a+=a
        else:
            assert(b<m)
            b+=b
    print("YES")
    print("0 0")
    print(a,"0")
    print("0",b)


n,m,k = map(int,input().split())
area = (n*m)/k
if(area != int(area) or area<=4):
    print("NO")
else:
    if(2*m)%k==0 and (2*m)//k<=m:
        print("YES")
        print("0 0")
        print(n,"0")
        print("0",2*m//k)
    elif(2*n)%k==0 and (2*n)//k<=n:
        print("YES")
        print("0 0")
        print(2*n//k,"0")
        print("0",m)
    else:
        print("NO")


def gcd(a,b):
    if(a==0):
        return b
    return gcd(b%a,a)

n,m,k = map(int,input().split())
flag = 1
if(k%2==0):
    flag = k%2
    k=k//2
if(n*m)%k!=0:
    print("NO")
else:
    s = gcd(n,k)
    k = k//s
    a = n//s
    s = gcd(m,k)
    k = k//s
    b = m//s
    if(flag == 1):
        if(a<n):
            a+=a
        else:
            b+=b
    print("YES")
    print("0 0")
    print(a,"0")
    print("0",b)


n,m,k = map(int,input().split())
area = (n*m)/k
if(area != int(area)):
    print("NO")
else:
    print("YES")
    print(m,"0")
    print("0",int(2*n/k))
    print("0 0")


n,m,k = map(int,input().split())
area = (n*m)/k
if(area != int(area) or area<=2):
    print("NO")
else:
    if(2*m)%k==0 and (2*m)//k<=m:
        print("YES")
        print("0 0")
        print(n,"0")
        print("0",2*m//k)
    elif(2*n)%k==0 and (2*n)//k<=n:
        print("YES")
        print("0 0")
        print(2*n//k,"0")
        print("0",m)
    else:
        print("NO")


def gcd(a,b):
    if(a==0):
        return b
    return gcd(b%a,a)

n,m,k = map(int,input().split())
area = (n*m)/k
flag = 0
if(k%2==0):
    flag = k%2
    k=k//2
if(n*m)%k!=0:
    print("NO")
else:
    s = gcd(n,k)
    k = k//s
    a = n//s
    s = gcd(m,k)
    k = k//s
    assert(k == 1)
    b = m//s
    if(flag):
        if(a<n):
            a+=a
        else:
            assert(b<m)
            b+=b
    print("YES")
    print("0 0")
    print(a,"0")
    print("0",b)


def gcd(a,b):
    if(a==0):
        return b
    return gcd(b%a,a)

n,m,k = map(int,input().split())
area = (n*m)/k
flag = 0
if(k%2==0):
    flag = k%2
    k=k//2
if(n*m)%k!=0:
    print("NO")
else:
    s = gcd(n,k)
    k = k//s
    a = n//s
    s = gcd(m,k)
    k = k//s
    b = m//s
    if(not (flag & 1)):
        if(a<n):
            a+=a
        else:
            b+=b
    print("YES")
    print("0 0")
    print(a,"0")
    print("0",b)