题目链接: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 方式调试,最后还有错可能就是思路上的问题。