题意给你一个字符串,对这个字符串有两种操作:
1.把逻辑位置(也就是对应字符串下标为pos-1)位于pos的字符改为c;
2.统计位于逻辑区间[L,R]的不同的字符个数;
其实已读完这个,我马上想到用前缀和,但是一想,好像不行吧,因为对于字符的修改你怎么办呢?
所以换了一种思路,我想着线段树可不可以,但是又想,线段树结点存什么呢?
所以行不通,之后看了大佬的代码,我彻底被折服了;QAQ;
整体思路:把每个字符对应的下标存下来,然后问到区间有多少个不同字符的时候,直接枚举+用二分查找就可以找到这个 区间有多少个不同字符了;
AC代码:
#include<bits/stdc++.h>
using namespace std;
set<int> Set[26];//放26个字符
int main(){
string s;
cin>>s;
for(int i=0;i<s.length();i++){
Set[s[i]-'a'].insert(i);//把 每个字符所占的下标给存起来
}
int n;
scanf("%d",&n);
int l,r,x;
char ch;
int op;
int ans;
for(int i=0;i<n;i++){
ans=0;
scanf("%d",&op);
if(op==1){//对于操作1 改变字符,需要删除逻辑位置x上的字符,然后把新的字符加入新字符对应的集合
scanf("%d %c",&x,&ch);
char t=s[x-1];
Set[t-'a'].erase(x-1);
s[x-1]=ch;
Set[ch-'a'].insert(x-1);
}else{
scanf("%d %d",&l,&r);//二分查找时间复杂度为:log(n)不用担心超时
l--;r--;
for(int i=0;i<26;i++){
if(Set[i].size()==0)continue;
set<int >::iterator it=Set[i].lower_bound(l);
if(it!=Set[i].end()&&*it<=r){
ans++;
}
}
printf("%d\n",ans);
}
}
return 0;
}