/**
 * Description: Dynamic String Hashing (Supports updating string characters)    
 * Usage: See below, update O(lg(N)), getHash O(lg(N))
 * Source: https://github.com/dragonslayerx 
 */

long long power(long long n, long long m, long long MOD)
{
    if (m == 0) return 1;
    long long x = power(n, m / 2, MOD);
    if (!(m & 1)) return (x * x) % MOD;
    else return (((x * x) % MOD) * n) % MOD;
}

const long long B = 100000007;
const long long M = 1000000009;
const long long invB = power(B-1, M-2, M); //inverse of B-1

long long pB[MAX];
void pInit() {
    pB[0] = 1;
    for (int i = 1; i < MAX; i++) {
        pB[i] = (pB[i-1] * B) % M;
    }
}

struct node {
    long long val;
    bool flag;
    long long lazy;
    node() {
        flag = false;
        val = lazy = 0;
    }
} st[4*MAX];

long long update(int n, int l, int r, int ql, int qr, int c) {
    if (st[n].flag) {
        st[n].val = (((st[n].lazy * (pB[r-l+1]+M-1) % M) % M) * invB) % M;
        if (l != r) {
            st[2*n+1].flag = true;
            st[2*n+1].lazy = st[n].lazy;
            st[2*n+2].flag = true;
            st[2*n+2].lazy = st[n].lazy;
        }
        st[n].flag = false;
        st[n].lazy = 0;
    }

    if (qr < l or ql > r) {
        return st[n].val;
    } else if (l >= ql and r <= qr) {
        st[n].val = (((c * (pB[r-l+1]+M-1) % M) % M) * invB) % M;
        if (l != r) {
            st[2*n+1].flag = true;
            st[2*n+1].lazy = c;
            st[2*n+2].flag = true;
            st[2*n+2].lazy = c;
        }
        return st[n].val;
    } else {
        int mid = (l + r)/2;
        long long leftHash = update(2*n+1, l, mid, ql, qr, c);
        long long rightHash = update(2*n+2, mid+1, r, ql, qr, c);
        st[n].val = ((leftHash * pB[r - mid]) % M + rightHash) % M;
        return st[n].val;
    }
}

long long getHash(int n, int l, int r, int ql, int qr) {
    if (st[n].flag) {
        st[n].val = (((st[n].lazy * (pB[r-l+1]+M-1) % M) % M) * invB) % M;
        if (l != r) {
            st[2*n+1].flag = true;
            st[2*n+1].lazy = st[n].lazy;
            st[2*n+2].flag = true;
            st[2*n+2].lazy = st[n].lazy;
        }
        st[n].flag = false;
        st[n].lazy = 0;
    }
    if (qr < l or ql > r) {
        return 0;
    } else if (l >= ql &&  r <= qr) {
        return (st[n].val * pB[qr - r]) % M;
    } else {
        int mid = (l + r)/2;
        long long leftHash = getHash(2*n+1, l, mid, ql, qr);
        long long rightHash = getHash(2*n+2, mid+1, r, ql, qr);
        long long h = (leftHash + rightHash) % M;
        return h;
    }
}

int main(){
    pInit();
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    char s[MAX];
    scanf("%s", s);
    for (int i = 0; i < n; i++) {
        update(0, 0, n-1, i, i, s[i] - '0');
    }
    for (int i = 0; i < m+k; i++) {
        int choice;
        scanf("%d", &choice);
        if (choice == 1){
            int l, r, c;
            scanf("%d%d%d", &l, &r, &c);
            l--, r--;
            update(0, 0, n-1, l, r, c);
        } else if (choice == 2) {
            int l, r, c;
            scanf("%d%d%d", &l, &r, &c);
            l--, r--;
            if (r-c < l) {
                printf("YES\n");
            } else {
                long long h1 = getHash(0, 0, n-1, l, r-c);
                long long h2 = getHash(0, 0, n-1, l+c, r);
                if (h1 == h2) {
                    printf("YES\n");
                } else {
                    printf("NO\n");
                }
            }
        }
    }
}