算法总在某个范围不大的维度上直接暴力。
这次的维度是字符集的大小,总共只有26个字符,所以直接用counting sort,其实这货也算是桶排吧,但是要能用这样的排序还有一个条件是不区分原子吧。
每次操作在制定的区间上,先查询出每个字符分别有多少个,然后按大小排列好。查询和排列用线段树维护,所以每次操作都是
O(logn)
的复杂度。最后从头到尾查一次就好了。
之前用Python写了这题,怎么都过不了,不开心。
#include <iostream>
using namespace std;
const int MAX_SIZE = 1e5 + 10;
#define m ((l + r) / 2)
#define lchild l, m, index * 2
#define rchild m + 1, r, index * 2 + 1
#define covered x <= l && r <= y
#define interact(l, r) x <= r && l <= y
class SegmentTree {
private:
int L, R, sum[MAX_SIZE << 2], lazy[MAX_SIZE << 2];
void set_lazy(int value, int l, int r, int index) {
sum[index] = value * (r - l + 1);
lazy[index] = value;
}
void push_down(int l, int r, int index) {
if (l != r && lazy[index] != -1) {
set_lazy(lazy[index], lchild);
set_lazy(lazy[index], rchild);
lazy[index] = -1;
}
}
void pull_up(int l, int r, int index) {
if (l != r) {
sum[index] = sum[index * 2] + sum[index * 2 + 1];
}
}
int query(int x, int y, int l, int r, int index) {
if (covered) {
return sum[index];
} else {
push_down(l, r, index);
int ans = 0;
if (interact(l, m)) {
ans += query(x, y, lchild);
}
if (interact(m + 1, r)) {
ans += query(x, y, rchild);
}
return ans;
}
}
void update(int x, int y, int value, int l, int r, int index) {
if (covered) {
set_lazy(value, l, r, index);
}
else {
push_down(l, r, index);
if (interact(l, m)) {
update(x, y, value, lchild);
}
if (interact(m + 1, r)) {
update(x, y, value, rchild);
}
pull_up(l, r, index);
}
}
public:
void clear(int l, int r) {
L = l;
R = r;
fill(sum, sum + MAX_SIZE, 0);
fill(lazy, lazy + MAX_SIZE, -1);
}
int query(int x, int y) {
return query(x, y, L, R, 1);
}
void update(int x, int y, int value) {
update(x, y, value, L, R, 1);
}
} trees[26];
string s;
int n, q, a, b, k, cnt[26];
int main(int argc, char const *argv[]) {
// freopen("miao.txt", "r", stdin);
while (cin >> n >> q) {
for (auto i = 0; i < 26; ++i) {
trees[i].clear(1, n);
}
cin >> s;
for (auto i = 0; i < s.length(); ++i) {
trees[s[i] - 'a'].update(i + 1, i + 1, 1);
}
for (auto _ = 0; q > _; _++) {
cin >> a >> b >> k;
fill(cnt, cnt + 26, 0);
for (auto i = 0; i < 26; ++i) {
cnt[i] = trees[i].query(a, b);
}
if (k == 1) {
auto current = a;
for (auto i = 0; i < 26; ++i) {
trees[i].update(a, b, 0);
trees[i].update(current, current + cnt[i] - 1, 1);
current += cnt[i];
}
} else {
auto current = a;
for (auto i = 25; 0 <= i; --i) {
trees[i].update(a, b, 0);
trees[i].update(current, current + cnt[i] - 1, 1);
current += cnt[i];
}
}
}
for (auto i = 1; i <= n; ++i) {
for (auto j = 0; j < 26; ++j) {
if (trees[j].query(i, i)) {
cout << (char)(j + 'a');
break;
}
}
}
cout << endl;
}
return 0;
}