D. Distinct Characters Queries(二分or树状数组)

题意:给个字符串,给两种操作,操作1:将字符串的第pos个字符值改成c,操作2:求[l,r]中的不同的字符数量。
1.自己的思路
开26个数组记录每个字符出现的位置,对于操作1,二分找到要在原字符的数组中删除的位置,二分找到在新字符的数组中插入的位置。对于操作2,对于26个字符分别二分,求出是否存在[l,r]之间的。然后效率比较慢,2000ms的题目勉强1800ms过了。
**

vector<vector<int> > v(26);
int main()
{
	string s;
	cin >> s;
	f(i, 0, s.size() - 1)
	{
		int now = s[i] - 'a';
		v[now].emplace_back(i);
	}
	int n;
	int op, x;
	char y;
	cin >> n;
	while (n--)
	{
		scanf("%d%d",&op, &x);
		if (op == 1)
		{
			getchar();
			scanf("%c", &y);
			int now = s[x - 1] - 'a';
			int pos = lower_bound(v[now].begin(), v[now].end(), x - 1) - v[now].begin();
			v[now].erase(v[now].begin() + pos);
			s[x - 1] = y;
			pos = upper_bound(v[y - 'a'].begin(), v[y - 'a'].end(), x - 1) - v[y-'a'].begin();
			v[y - 'a'].insert(v[y-'a'].begin()+pos,x-1);
		}
		else
		{
			int l = x;int r;scanf("%d", &r);
			int ans = 0;
			l--;
			r--;
			f(i, 0, 25)
			{
				int pos = lower_bound(v[i].begin(), v[i].end(), l) - v[i].begin();
				if (pos == v[i].size())continue;
				if (v[i][pos] <= r)ans++;
			}
			printf("%d\n", ans);
		}
	}
	return 0;
}

2.正解,树状数组维护前缀
对于操作1,无非是将所有pos大于l的关于字符c的前缀加减1,直接用树状数组维护。对于操作2,则是直接对26个字符求区间是否存在。。。

int tree[26][N];
int n,m;
void add(int k, int c,int num)
{
	for (int i = k;i <= m; i += i & -i)
		tree[c][i] += num;

}
int read(int k,int c)
{
	int sum = 0;
	for (int i = k;i > 0; i -= i & -i)
		sum += tree[c][i];
	return sum;
}
int main()
{
	string s,x;
	cin >> x >> n;
	s = '?' + x;
	m = (int)s.size()-1;
	f(i, 1, s.size()-1)
	{
		add(i, s[i] - 'a', 1);
	}
	int op, l, r;
	char c;
	f(i, 1, n)
	{
		scanf("%d%d", &op, &l);
		if (op == 1)
		{
			getchar();
			scanf("%c", &c);
			add(l, s[l] - 'a', -1);
			add(l, c-'a', 1);
			s[l] = c;
		}
		else
		{
			scanf("%d", &r);	
			int ans = 0;
			f(i, 0, 25)
			{
				if (read(r, i) - read(l - 1, i) >= 1)ans++;
			}
			printf("%d\n", ans);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值