// 简要原理
string s,t;
const ull P=131;
vector<ull> pre(n+1); // pre[x] = pow(P,x);
h1(s+t) = h1(s)*pre[t.length()] + h1(t);
h2(s+t) = h2(t)*pre[s.length()] + h2(s);
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define endl '\n'
#define lc p<<1
#define rc p<<1|1
const ull P=131;
const int N=1e6+10;
vector<ull> pre;
string str;
struct node
{
int l,r;
ull h1,h2;
}tr[4*N];
void pushup(int p)
{
int len1=tr[lc].r-tr[lc].l+1;
int len2=tr[rc].r-tr[rc].l+1;
tr[p].h1=tr[lc].h1*pre[len2]+tr[rc].h1;
tr[p].h2=tr[rc].h2*pre[len1]+tr[lc].h2;
}
void build(int p, int x, int y)
{
tr[p]={x,y,str[x],str[x]};
if(x==y)
return;
int mid=x+y>>1;
build(lc,x,mid);
build(rc,mid+1,y);
pushup(p);
}
void update(int p, int x, ull k)
{
if(tr[p].l==tr[p].r)
{
tr[p].h1=tr[p].h2=k;
return;
}
int mid=tr[p].l+tr[p].r>>1;
if(x<=mid) update(lc,x,k);
else update(rc,x,k);
pushup(p);
}
vector<ull> query(int p, int x, int y)
{
if(x<=tr[p].l && tr[p].r<=y)
return {tr[p].h1,tr[p].h2,tr[p].r-tr[p].l+1};
int mid=tr[p].l+tr[p].r>>1;
if(x>mid) return query(rc,x,y);
if(y<=mid) return query(lc,x,y);
auto wl=query(lc,x,y);
auto wr=query(rc,x,y);
vector<ull> res(3);
int len1=wl[2], len2=wr[2];
res[0]=wl[0]*pre[len2]+wr[0]; // h1
res[1]=wr[1]*pre[len1]+wl[1]; // h2
res[2]=len1+len2; // len
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,m;
cin>>n>>m>>str;
str=' '+str;
n++;
pre.resize(n+1);
pre[0]=1;
for(int i=1;i<=n;i++)
pre[i]=pre[i-1]*P;
build(1,1,n);
while(m--)
{
char ch;
int opt,k,l,r;
cin>>opt;
if(opt==1)
{
cin>>k>>ch;
update(1,k,ch);
}
else
{
cin>>l>>r;
auto x=query(1,l,r);
cout<<(x[0]==x[1] ? "Yes" : "No")<<endl;
}
}
}