题解 P2787 【语文1(chin1)- 理理思维】
珂朵莉树好题!
区间推平往往是珂朵莉树的标志,没学过可以看一下这个大佬的讲解。
注意本题“大小写不敏感”,读入字母时应注意大小写转化。
op == 1
取出区间
op == 2
这就是珂朵莉树基本操作assign,在此不再赘述。
op == 3
珂朵莉树的储存方式其实是类似一个桶的,而本题元素只有26个,所以使用桶排要简洁高效的多。
取出区间
#include <bits/stdc++.h>
#define IT set<Node>::iterator
using namespace std;
int c(char x)
{
if ('a'<=x && x<='z') return x - 'a';
return x - 'A';//大小写敏感的转化
}
struct Node
{
mutable int L, R, z;
int operator <(const Node &a) const{
return L < a.L;
}
};
set <Node> a;
IT split(int p)
{
auto it = a.lower_bound(Node{p, 0, 0});
if (it != a.end() && it->L==p) return it;
--it;
Node x = *it; a.erase(it);
a.insert(Node{x.L, p-1, x.z});
return a.insert(Node{p, x.R, x.z}).first;
}
int N, M, op, x, y, z, B[27];
char xc;
int main()
{
cin >> N >> M;
for (int i = 1; i <= N; i++)
{
cin >> xc;
a.insert(Node{i, i, c(xc)});
}
for (int i = 1; i <= M; i++)
{
cin >> op >> x >> y;
if (op == 3)
{
memset(B, 0, sizeof B);//清空桶
auto itr = split(y+1), itl = split(x);
while (itl != itr)
{
B[itl->z] += itl->R - itl->L + 1;
itl = a.erase(itl);//C++11的erase可以在删除元素后返回下一个元素,省去itl++。
}
for (int i = 0; i < 26; i++)
if (B[i])
{
a.insert(Node{x, x + B[i]-1, i});//从左端点往后插入
x += B[i];
}
continue;
}
cin >> xc, z = c(xc);
if (op == 1)
{
int ans = 0;
auto itr = split(y+1), itl = split(x);
for (; itl != itr; itl++)
if (itl->z == z) ans += itl->R - itl->L + 1;//暴力遍历查找
printf("%d\n", ans);
}
if (op == 2)
{//珂朵莉树基本操作assign
auto itr = split(y+1), itl = split(x);
a.erase(itl, itr);
a.insert(Node{x, y, z});
}
}
}