[ABC285F] Substring of Sorted String 题解
目前题解区唯一一篇未使用树状数组/线段树的题解。
题目大意
给定一个长度为
1 x c:将字符串S 中的第x 个字符替换为c 。2 l r:将S 中的字符按升序排列,得到新字符串T ,询问串S_{l,l+1,\cdots,r} 是否为T 的子串。
对于每个操作 Yes 或者 No 表示结果。
解题思路
先来考虑
于是很多题解开始用树状数组和线段树开始维护,但是实际上我们可以用 set 来维护这个玩意儿。用一个 set 维护所有
代码示例
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,q;
string s;
set<int> x,id[30];
signed main(){
cin>>n>>s>>q;
s=" "+s;
for(int i=2;i<s.size();i++) if(s[i]<s[i-1]) x.insert(i);//用于检查区间是否单调不降
for(int i=1;i<s.size();i++) id[s[i]-'a'].insert(i);
while(q--){
int op,l,r;
char c;
cin>>op;
if(op==1){
cin>>l>>c;
if(l!=1) if(s[l]<s[l-1]) x.erase(l);
if(l!=s.size()-1) if(s[l+1]<s[l]) x.erase(l+1);
id[s[l]-'a'].erase(l);
//维护修改这一位字符造成的影响
s[l]=c;//修改
//维护修改这一位字符造成的影响
id[s[l]-'a'].insert(l);
if(l!=s.size()-1) if(s[l+1]<s[l]) x.insert(l+1);
if(l!=1) if(s[l]<s[l-1]) x.insert(l);
}else{
int flg=1;
cin>>l>>r;
char Min='z',Max='a';
//找到区间中出现的最大最小字符
for(char ck='a';ck<='z';ck++){
auto it=id[ck-'a'].lower_bound(l);
if(it!=id[ck-'a'].end()&&*it<=r){
if(ck<Min) Min=ck;
if(ck>Max) Max=ck;
}
}
//判断其余字符出现次数是否等于总出现次数
//不等于则答案为 No
for(char ck=Min+1;ck<=Max-1;ck++){
if(id[ck-'a'].empty()) continue;
if((l<=*id[ck-'a'].begin()&&*id[ck-'a'].rbegin()<=r)) continue;
flg=0;
}
auto it=x.upper_bound(l);
if(it!=x.end()&&*it<=r) flg=0;
//区间不单调不降则答案为 No
cout<<(flg?"Yes":"No")<<endl;
}
}
return 0;
}