一道比较简单好想的数据结构。
我们不妨先分析 T T T 串的性质,由题意得 T T T 的字母是递增的,那意味着我询问的子串也应该递增的。
但是子串递增并不意味着他是 T T T 的子串,因为排序后可能会有其他的字母插入进来。举个例子:
S = a a a a a a b b b b d d y y y y z z z f f b a a a z T = a a a a a a a a a b b b b b d d f f y y y y z z z z \begin{aligned} S=\tt{aaaaaabbbbddyyyyzzzffbaaaz}\\ T=\tt{aaaaaaaaabbbbbddffyyyyzzzz} \end{aligned} S=aaaaaabbbbddyyyyzzzffbaaazT=aaaaaaaaabbbbbddffyyyyzzzz
假设我们现在查询 a a b b b b d d y y \tt{aabbbbddyy} aabbbbddyy 这个子串是否是 T T T 的一个子串。
我们不难发现将 S S S 串排序后发生了以下几个事情:
- a \tt a a 和 z \tt z z 被归位了,看上去并不影响我们的查询。
- b \tt b b 被塞了一个进去。
- f \tt f f 被塞了两个进去,但是我们原本的子串并没有 f \tt f f。
所以经过简单的分析,我们得到如下结论:
- 在 S l + 1 S_l+1 Sl+1 到 S r − 1 S_r-1 Sr−1 的所有字母中,其在子串中的出现次数应当等于全串的出现次数。
- 跟 S l S_l Sl 和 S r S_r Sr 相同的字母不影响查询。
- 区间要递增。
看上去“区间递增”是最好做的,不妨想一下如何用数据结构维护。
- 如果 S i ⩾ S i − 1 S_i\geqslant S_{i-1} Si⩾Si−1,那么我们令 a i : = 1 a_i:=1 ai:=1,否则 a i : = − 1 a_i:=-1 ai:=−1。
那么一个区间 [ l , r ] [l,r] [l,r] 递增的条件可以转化为 ∑ l + 1 r a i = r − l \sum\limits_{l+1}^r a_i=r-l l+1∑rai=r−l。开一个线段树维护即可,每次询问都要检查如上条件,修改时考虑新的字符与其前后的关系,要更改两处线段树的值。
“出现次数”这个条件就十分简单了,不难发现值域只有 26 26 26,可以考虑开 26 26 26 个线段树或者树状数组(我知道大家懒得写所以还是写树状数组吧)。每一个树状数组维护一个值,如果串中 S i = p S_i=p Si=p,那么 t r p , i = 1 tr_{p,i}=1 trp,i=1,累加起来即可得到出现次数。
//F
#include<bits/stdc++.h>
#define int long long
#define mid ((l+r)>>1)
#define fir first
#define sec second
#define lowbit(i) (i&(-i))
using namespace std;
const int N=5e5+5;
const int inf=1e18;
struct edge{int to,nxt,l;};
inline int read(){
char op=getchar();
int w=0,s=1;
while(op<'0'||op>'9'){
if(op=='-') s=-1;
op=getchar();
}
while(op>='0'&&op<='9'){
w=(w<<1)+(w<<3)+op-'0';
op=getchar();
}
return w*s;
}
int a[N],n;
char s[N];
void change(int p,int l,int r,int x,int k){
if(l==x&&r==x){
a[p]=k;
return;
}
if(x<=mid) change(p<<1,l,mid,x,k);
else change(p<<1|1,mid+1,r,x,k);
a[p]=a[p<<1]+a[p<<1|1];
}
int ask(int p,int l,int r,int x,int y){
int ans=0;
if(x<=l&&r<=y){
ans+=a[p];
return ans;
}
if(x<=mid) ans+=ask(p<<1,l,mid,x,y);
if(y>mid) ans+=ask(p<<1|1,mid+1,r,x,y);
return ans;
}
struct bit_tree{
int a[N];
void change(int x,int k){
for(register int i=x;i<=n;i+=lowbit(i)) a[i]+=k;
return;
}
int ask(int x){
int ans=0;
for(register int i=x;i>=1;i-=lowbit(i)) ans+=a[i];
return ans;
}
}st[28];
signed main(){
n=read();
scanf("%s",s+1);
for(register int i=1;i<=n;i++){
if(i>=2){
if(s[i]>=s[i-1]) change(1,1,n,i,1);
else change(1,1,n,i,-1);
}
st[s[i]-'a'+1].change(i,1);
}
int q=read();
while(q--){
int op=read();
if(op==2){
int l=read(),r=read();
if(ask(1,1,n,l+1,r)!=r-l){
printf("No\n");
continue;
}
bool p=true;
for(register int i=s[l]+1;i<=s[r]-1;i++){
if(st[i-'a'+1].ask(r)-st[i-'a'+1].ask(l-1)!=st[i-'a'+1].ask(n)){
printf("No\n");
p=false;
break;
}
}
if(p){
printf("Yes\n");
continue;
}
}else{
int x=read();
char ch=getchar();
while(ch>'z'||ch<'a') ch=getchar();
if(ch>=s[x-1]) change(1,1,n,x,1);
else change(1,1,n,x,-1);
if(x<n){
if(s[x+1]>=ch) change(1,1,n,x+1,1);
else change(1,1,n,x+1,-1);
}
st[s[x]-'a'+1].change(x,-1);
st[ch-'a'+1].change(x,1);
s[x]=ch;
}
}
}