Codeforces 899F Letters Removing

链接

传送门

题意

给出一个长度为$n(1 \leq n \leq 2 \cdot 10^5)$的字符串,进行$m(1 \leq m \leq 2 \cdot 10^5)$次删除操作,每个删除操作将删除当前字符串$l$到$r$间所有字符$c$。输出$m$次操作之后的字符串。

思路

对每种字符都用set存下出现的位置,用树状数组来计算位置$x$前有多少个未被删除的字符。对于每次删除操作,利用树状数组将位置$l$和$r$转换为初始字符串中的位置,然后在set中删除并更新字符串和树状数组。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
typedef long long LL;
using namespace std;
const int maxn = 200010;
const int maxm = 260;
int n, m;
int bit[maxn];
char str[maxn];
set<int> s[maxm];
inline int lowbit(int& x) {
return x & (-x);
}
int sum(int i) {
int res = 0;
while (i > 0) {
res += bit[i];
i -= lowbit(i);
}
return res;
}
void add(int i, int x) {
while(i <= n){
bit[i] += x;
i += lowbit(i);
}
return;
}
int getPos(int x) {
int L = x, R = n, m = x;
while (L <= R) {
m = (L + R) / 2;
if (sum(m) >= x) {
R = m - 1;
} else {
L = m + 1;
}
}
return L;
}
int main() {
scanf("%d%d", &n, &m);
scanf("%s", str + 1);
for (int i = 1; str[i]; ++i) {
s[str[i]].insert(i);
add(i, 1);
}
int l, r;
char tmp[5];
while (m--) {
scanf("%d%d%s", &l, &r, tmp);
l = getPos(l);
r = getPos(r);
auto lb = s[tmp[0]].lower_bound(l);
auto ub = s[tmp[0]].upper_bound(r);
while (lb != ub) {
add(*lb, -1);
str[*lb] = 0;
++lb;
}
s[tmp[0]].erase(s[tmp[0]].lower_bound(l), ub);
}
for (int i = 1; i <= n; ++i) {
if (str[i]) {
putchar(str[i]);
}
}
puts("");
return 0;
}

支付宝扫码领红包