You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
3.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 柯朵莉树即使吸氧也过不是最后一个测试点TLE
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5;
// 柯朵莉树模板
struct Node {
int l, r; // l和r表示这一段的起点和终点
mutable int v; // v表示这一段上所有元素相同的值是多少,注意关键字 mutable,使得set中结构体属性可修改
bool operator<(const Node &b) const {
return l < b.l; // 规定按照每段的左端点排序
}
};
set<Node> s; // 柯朵莉树的区间集合
// 分裂:[l,x-1],[x,r]
set<Node>::iterator split(int x) {
auto it = s.lower_bound({x});
if (it != s.end() && it->l == x) return it; // 一击命中
it--; // 没有找到就减1个继续找
if (it->r < x) return s.end(); // 真的没找到,返回s.end()
int l = it->l, r = it->r, v = it->v; // 没有被返回,说明找到了,记录下来,防止后面删除时被破坏
s.erase(it); // 删除整个区间
s.insert({l, x - 1, v}); //[l,x-1]拆分
// insert函数返回pair其中的first是新插入结点的迭代器
return s.insert({x, r, v}).first; //[x,r]拆分
}
// 区间加
void add(int l, int r, int v) {
// 必须先计算itr,后计算itl
auto R = split(r + 1), L = split(l);
for (auto it = L; it != R; it++) it->v += v;
}
// 区间赋值
void assign(int l, int r, int v) {
auto R = split(r + 1), L = split(l);
s.erase(L, R); // 删除旧区间
s.insert({l, r, v}); // 增加新区间
}
// 查询字符k出现的次数
int getcnt(int l, int r, char k) {
auto R = split(r + 1), L = split(l);
int res = 0;
for (; L != R; L++) res += (L->v == k) ? L->r - L->l + 1 : 0; // 暴力统计值为k的个数
return res;
}
int b[26]; // 计数用的桶共26个字符
void px(int l, int r) { // 将区间[l,r]之间的字符进行排序
memset(b, 0, sizeof b); // 多次使用,每次使用前清空
auto R = split(r + 1), L = split(l);
for (auto it = L; it != R; it++) b[it->v - 'A'] += it->r - it->l + 1; // 用桶来统计计数
s.erase(L, R); // 将旧区间删除掉
int pos = l;
for (int i = 0; i < 26; i++) // 由小到大枚举每个字符A~Z然后插入A的数量B的数量也就是完成了a~z的排序
if (b[i]) {
s.insert({pos, pos + b[i] - 1, i + 'A'});
pos += b[i];
}
}
// 学习到cin可以结合char[]进行操作如果想把下标0的位置让出来就直接cin>>ch+1
int main() {
#ifndef ONLINE_JUDGE
freopen("P2787.in", "r", stdin);
#endif
// 加快读入
ios::sync_with_stdio(false), cin.tie(0);
int n, m;
char x;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> x;
if (x >= 'a') x -= 'a' - 'A'; // 本题输入不区分大小写,所以,输入的小写字母统一换成大写字母
s.insert({i, i, x});
}
char k;
while (m--) {
int op, l, r;
cin >> op >> l >> r;
if (op != 3) {
cin >> k;
if (k >= 'a') k -= 'a' - 'A';
}
if (op == 1)
printf("%d\n", getcnt(l, r, k)); // 查询k出现的次数
else if (op == 2)
assign(l, r, k); // 全部替换为k
else
px(l, r); // 按照a~z的顺序排序
}
return 0;
}