题目链接:https://vjudge.net/contest/331024#problem/E
翻译:
给定一个字符串,进行2种操作
1 pos c:用字符c替代字符串pos位置上的字符。
2 l r:计算字符串[l,r]区间上不同字符的数量,并输出。
思路:
此题的关键是如何计算给定区间上不同字符的数量。可以考虑树状数组。
遍历字符串,对于每一个字符将它分配到树状数组对应的区间,并计算它出现的次数。所以引入了book数组。book[i][j]:对于区间i,字符转化为j,原字符出现的次数。
此题之所以可以这样做,关键题上说明字符串全部为小写字母。总共有26个小写字母,对于求给定区间不同字符的数量,只需要遍历26个字母即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+1;
char a[N];
int book[N][30],len;
void build(int c,int x)
{
while(x<=len)
{
book[x][c]++;/*对于区间x,每一个字符的数量*/
x+=x&(-x);
}
}
void update(int x,int c,int init)/*x位置的字符用c代替,x位置原来的字符为init*/
{
while(x<=len)
{
book[x][init]--;
book[x][c]++;
x+=x&(-x);
}
}
int quary(int l,int r)
{
int m1[30]= {0},m2[30]= {0},ans=0;
while(l>0)
{
for(int i=1; i<=26; i++)
m1[i]+=book[l][i];
l-=l&(-l);
}
while(r>0)
{
for(int i=1; i<=26; i++)
m2[i]+=book[r][i];
r-=r&(-r);
}
for(int i=1; i<=26; i++)
{
if(m2[i]>m1[i])
ans++;
}
return ans;
}
int main()
{
while(~scanf("%s",a+1))
{
memset(book,0,sizeof(book));
int q;
len=strlen(a+1);
for(int i=1; i<=len; i++)
build(a[i]-96,i);
scanf("%d",&q);
while(q--)
{
int lab;
scanf("%d",&lab);
if(lab==1)
{
char ch[10];
int pos;
scanf("%d%s",&pos,ch);
update(pos,ch[0]-96,a[pos]-96);
a[pos]=ch[0];
}
else
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",quary(l-1,r));
}
}
}
return 0;
}