#590 (Div. 3) D.Distinct Characters Queries (树状数组)

题目描述

You are given a string s consisting of lowercase Latin letters and q queries for this string.
Recall that the substring s[l;r] of the string s is the string slsl+1…sr. For example, the substrings of “codeforces” are “code”, “force”, “f”, “for”, but not “coder” and “top”.
There are two types of queries:
1 pos c (1≤pos≤|s|, c is lowercase Latin letter): replace spos with c (set spos:=c);
2 l r (1≤l≤r≤|s|): calculate the number of distinct characters in the substring s[l;r].

Input

The first line of the input contains one string s consisting of no more than 105 lowercase Latin letters.
The second line of the input contains one integer q (1≤q≤105) — the number of queries.
The next q lines contain queries, one per line. Each query is given in the format described in the problem statement. It is guaranteed that there is at least one query of the second type.

Output

For each query of the second type print the answer for it — the number of distinct characters in the required substring in this query.

Examples

Input
abacaba
5
2 1 4
1 4 b
1 5 b
2 4 6
2 1 7
Output
3
1
2
Input
dfcbbcfeeedbaea
15
1 6 e
1 4 b
2 6 14
1 7 b
1 12 c
2 6 8
2 1 6
1 7 c
1 2 f
1 10 a
2 7 9
1 10 a
1 14 b
1 1 f
2 1 11
Output
5
2
5
2
6

题目大意

给你一个字符串s,和q组询问/指令。
指令1:输入pos和字符c,然后将s中pos位置的字符改为c。
指令2:输入l和r,然后找出s的[l,r]区间中有多少种字符。

题目分析

快速的区间查询+修改,很容易就能想到树状数组,但是想到了树状数组这个题还是不太好做的。还有一个关键的问题是:怎么查询字符的种类。
我们可以用维护26个树状数组,每个树状数组只储存一种字符的情况,当查询时我们可以遍历26个数组的对于区间,看看该区间上是否存在该字符。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <iomanip>
#define LL long long
#define PII pair<int,int>
using namespace std;
const int N=1e5+5;
int len;
char s[N];
int tr[26][N];
int lowbit(int x)
{
	return x & -x;
}
void add(int k,int x,int c)	//k记录该字符对应哪一个树状数组,x记录位置
{
	for(int i=x;i<=len;i+=lowbit(i))
		tr[k][i]+=c;
}
int sum(int k,int x)
{
	int res=0;
	for(int i=x;i>0;i-=lowbit(i))
		res+=tr[k][i];
	return res;
}
int main()
{
	scanf("%s",s+1);
	len=strlen(s+1);
	for(int i=1;i<=len;i++)		//树状数组的建立,注意不同的字符要插入不同的数组中
		add(s[i]-'a',i,1);
	
	int q;
	scanf("%d",&q);
	while(q--)
	{
		int op;
		scanf("%d",&op);
		if(op==1)		//修改操作
		{
			int pos;
			char c;
			scanf("%d %c",&pos,&c);
			add(s[pos]-'a',pos,-1);		//删去原来的字符
			add(c-'a',pos,1);			//添加新的字符
			s[pos]=c;					//修改字符串
		}
		else			//查询操作
		{
			int l,r;
			scanf("%d %d",&l,&r);
			int res=0; 
			for(int i=0;i<26;i++)		//如果该区间中某个字符的数量大于0,那么res++
				if(sum(i,r)-sum(i,l-1)>=1) res++;
			
			printf("%d\n",res);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值