题目
题目大意: 给定一个长度不超过 1 0 5 10^5 105的字符串(小写英文字母),和不超过 50000 50000 50000个操作。
每个操作 L R K L\ R\ K L R K 表示给区间 [ L , R ] [L,R] [L,R]的字符串排序, K = 1 K=1 K=1为升序, K = 0 K=0 K=0为降序。
最后输出最终的字符串。
题解
- 刚看题的时候一点思路都没有
只会暴力sort,后来根据复杂度开始 y y yy yy算法,然后想到了线段树 q w q qwq qwq - 由于字母个数只有26个,我们可以对每个字母建一棵权值线段树,记录每个字母在区间内的出现次数, 对与升序,正序循环区间覆盖即可。
c o d e code code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 100;
const int M = 4e5 + 100;
template <class T>
inline void read(T &s) {
s = 0; T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
int n, q;
char ch[N];
int add[30][M], sum[30][M];
inline void push_up(int p, int id) {
sum[id][p] = sum[id][p<<1] + sum[id][p<<1|1];
return ;
}
void build(int p, int l, int r) {
if (l == r) {
int id = ch[l] - 'a' + 1;
sum[id][p] = 1;
return ;
}
int mid = (l + r) >> 1;
build(p<<1, l, mid);
build(p<<1|1, mid + 1, r);
for (int i = 1; i <= 26; ++i) push_up(p, i);
}
inline void push_down(int p, int l, int r, int id) {
if (add[id][p] != -1) {
int mid = (l + r) >> 1;
sum[id][p<<1] = add[id][p] * (mid - l + 1);
sum[id][p<<1|1] = add[id][p] * (r - mid);
add[id][p<<1] = add[id][p];
add[id][p<<1|1] = add[id][p];
add[id][p] = -1;
}
}
void update(int p, int l, int r, int ql, int qr, int w, int id) {
if (ql <= l && qr >= r) {
sum[id][p] = w * (r - l + 1);
add[id][p] = w;
return ;
}
push_down(p, l, r, id);
int mid = (l + r) >> 1;
if (ql <= mid) update(p<<1, l, mid, ql, qr, w, id);
if (qr > mid) update(p<<1|1, mid + 1, r, ql, qr, w, id);
push_up(p, id);
}
int query(int p, int l, int r, int ql, int qr, int id) {
if (ql <= l && qr >= r) return sum[id][p];
push_down(p, l, r, id);
int mid = (l + r) >> 1;
int val = 0;
if (ql <= mid) val += query(p<<1, l, mid, ql, qr, id);
if (qr > mid) val += query(p<<1|1, mid + 1, r, ql, qr, id);
return val;
}
void output(int p, int l, int r) {
if (l == r) {
for (int i = 1; i <= 26; ++i) {
if (sum[i][p]) {
ch[l] = (char)(i + 'a' - 1);
break;
}
}
return ;
}
for (int i = 1; i <= 26; ++i)
push_down(p, l, r, i);
int mid = (l + r) >> 1;
output(p<<1, l, mid);
output(p<<1|1, mid + 1, r);
}
int main() {
read(n), read(q);
scanf("%s", ch + 1);
memset(add, -1, sizeof(add));
build(1, 1, n);
while (q--) {
int l, r, opt;
read(l), read(r), read(opt);
if (opt) { // 升序
int tmp = l;
for (int i = 1; i <= 26; ++i) {
int cnt = query(1, 1, n, l, r, i);
if (!cnt) continue;
update(1, 1, n, l, r, 0, i);
update(1, 1, n, tmp, tmp + cnt - 1, 1, i);
tmp += cnt;
}
}
else { // 降序
int tmp = l;
for (int i = 26; i >= 1; --i) {
int cnt = query(1, 1, n, l, r, i);
if (!cnt) continue;
update(1, 1, n, l, r, 0, i);
update(1, 1, n, tmp, tmp + cnt - 1, 1, i);
tmp += cnt;
}
}
}
output(1, 1, n);
for (int i = 1; i <= n; ++i)
putchar(ch[i]);
return 0;
}
/*
4 1
abcd
1 4 1
*/