Codeforces Round #590 (Div. 3)_D_线段树

题目链接:https://codeforces.com/contest/1234/problem/D

解题过程:
看到这道题目,因为字母的总数只有26个,所以我就直接用线段树维护了长度为26的数组,用来记录这个区间里面所有字母的总的个数,这样我们可以直接维护l, r区间的所有的字母字母的数量,然后在查询的时候可以直接用 (1, r) - (1, l - 1),就得到 l - r 区间里面不同字母的个数。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn = 1e5 + 5;

char str[maxn], op[3];
int n, l, r, x, fi[30], permt[30], tmp_permt[30];
struct SegmentTree {int l, r, a[30]; }t[maxn * 4];

inline void build(int s, int l, int r) {
	t[s].l = l, t[s].r = r;
	for(int i = 0; i <= 26; i ++)
		t[s].a[i] = 0;
	if(l == r) return;

	int mid = (l + r) / 2;
	build(s * 2, l, mid);
	build(s * 2 + 1, mid + 1, r);
}

inline void insert(int s, int l, int r, int x) {
	if(l <= t[s].l && r >= t[s].r) {
		t[s].a[x] ++;
		return;
	}

	int mid = t[s].l + t[s].r >> 1;
	if(l <= mid) insert(s * 2, l, r, x);
	else insert(s * 2 + 1, l, r, x);
	t[s].a[x] = t[s * 2].a[x] + t[s * 2 + 1].a[x];
}

inline void change(int s, int l, int r, int y, int x) {
	if(l <= t[s].l && r >= t[s].r) {
		t[s].a[x] ++;
		t[s].a[y] --;
		return;
	}

	int mid = (t[s].l + t[s].r) >> 1;
	if(l <= mid) {
		change(s * 2, l, r, y, x);
		t[s].a[x] = t[s * 2].a[x] + t[s * 2 + 1].a[x];
		t[s].a[y] = t[s * 2].a[y] + t[s * 2 + 1].a[y];
	} else {
		change(s * 2 + 1, l, r, y, x);
		t[s].a[x] = t[s * 2].a[x] + t[s * 2 + 1].a[x];
		t[s].a[y] = t[s * 2].a[y] + t[s * 2 + 1].a[y];
	}
}

inline void query(int s, int l, int r) {
	if(l <= t[s].l && r >= t[s].r) {
		for(int i = 0; i <= 26; i ++)
			permt[i] += t[s].a[i];
		return;
	}

	int mid = (t[s].l + t[s].r) / 2;
	if(l <= mid) query(s * 2, l, r);
	if(mid < r) query(s * 2 + 1, l, r);
}

inline void out(void) {
	for(int i = 0; i <= 26; i ++) permt[i] = 0;
	query(1, 1, 15);
	for(int i = 0; i <= 26; i ++)
		printf("%d%c  ", permt[i], i + 'a');
	puts("");
	for(int i = 0; i <= 26; i ++) permt[i] = 0;
}

int main(void) {
//	freopen("in.txt", "r", stdin);
	scanf("%s", str + 1);
	scanf("%d", &n);
 
	build(1, 1, strlen(str + 1));
	for(int i = 1; i <= strlen(str + 1); i ++) 
		insert(1, i, i, str[i] - 'a');

	for(int i = 1; i <= n; i ++) {
		scanf("%s", op);
		if(op[0] == '1') {
			scanf("%d%s", &x, op);
			change(1, x, x, str[x] - 'a', op[0] - 'a');
			str[x] = op[0];
		} else {
			memset(permt, 0, sizeof permt);
			scanf("%d%d", &l, &r);
			int sum = 0;
			query(1, 1, r);
			memcpy(tmp_permt, permt, sizeof permt);
			memset(permt, 0, sizeof permt);
			query(1, 1, l - 1);
			for(int i = 0; i <= 26; i ++) {
				tmp_permt[i] -= permt[i];
				if(tmp_permt[i] > 0) sum ++;
			}
			
			printf("%d\n", sum);	
		}
	}
	
	return 0;
}

总结:
其实这道题目我想加写的时间可能还不到10分钟,但是我调试代码的时候调了1个小时左右,最后还是没有调出来,最后我有重新检查了一遍,发现问题出现在了我在比赛的时候从来没有想过的点上,即change的时候忘了把原字符串一起改。所以我们在检查的时候一定要先从头道为仔细地检查一遍,确认没有问题了之后可以再使用cout 方式调试,最后还有错可能就是思路上的问题。

发布了136 篇原创文章 · 获赞 0 · 访问量 2991

猜你喜欢

转载自blog.csdn.net/weixin_42596275/article/details/102084046