CodeForces 558E A Simple Task 线段树 桶排思想
CodeForces 558E A Simple Task 线段树 桶排思想
题意
给定长度不超过\(10^5\)的字符串(小写英文),和不超过\(10^5\)的操作。
每次操作对\([L,R]\)区间的字符排序,\(K = 1\)表示升序,\(K = 0\) 表示降序。
分析
一般这种题可以转化着去做,即不要真的去排序。
但是考虑到此题的特殊性(字符集非常小),想到用桶排的思想。
对于一段区间,首先把在这段区间的某个字母全部拿出来(桶),然后依次按顺序放到区间里(排)。
到此题,相当于要进行区间修改和区间查询,想到用线段树即可。
开26个线段树表示字母的出现位置,对于查询\([l,r]\),从小到大排,若有\(num\)个,就排在\([l + cur + num,l + cur + num-1]\)
如果是降序,那么反一下就好了。
代码
#include<bits/stdc++.h>
#define eps 1e-8
#define equals(a,b) (fabs(a - b) < eps)
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
ll rd(){
ll x = 0;
int f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == -1) f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
int cur;
struct SegmentTree{
int n;
vector<int> sum,tag;
SegmentTree(){}
SegmentTree(int n):n(n),sum(((n + 1) << 2)),tag(((n + 1) << 2),-1) {}
int push_up(int i){
sum[i] = sum[i << 1] + sum[i << 1|1];
}
void update(int i,int l,int r,int v){
sum[i] = (r - l + 1) * v;
tag[i] = v;
}
void push(int i,int l,int r){
int mid = l + r >> 1;
if(tag[i] != -1) {
update(i << 1,l,mid,tag[i]);
update(i << 1|1,mid + 1,r,tag[i]);
tag[i] = -1;
}
}
void update(int i,int l,int r,int L,int R,int v){
if(l > R || r < L) return;
if(l >= L && r <= R) return update(i,l,r,v);
int mid = l + r >> 1;
push(i,l,r);
update(i << 1,l,mid,L,R,v);
update(i << 1|1,mid + 1,r,L,R,v);
push_up(i);
}
int query(int i,int l,int r,int L,int R){
if(l > R || r < L) return 0;
if(l >= L && r <= R) return sum[i];
int mid = l + r >> 1;
push(i,l,r);
return query(i << 1,l,mid,L,R) + query(i << 1|1,mid + 1,r,L,R);
}
};
char s[100005];
SegmentTree seg[26];
int main(){
int n = rd();
int m = rd();
for(int i = 0;i < 26;i++)
seg[i] = {n};
scanf("%s",s);
for(int i = 0;i < n;i++)
seg[s[i] - 'a'].update(1,1,n,i + 1,i + 1,1);
while(m--){
cur = 0;
int l = rd();
int r = rd();
int k = rd();
if(k == 1) {
for(int i = 0;i < 26;i++){
int num = seg[i].query(1,1,n,l,r);
if(!num) continue;
seg[i].update(1,1,n,l,r,0);
seg[i].update(1,1,n,l + cur,l + cur + num - 1,1);
cur += num;
}
}
else{
for(int i = 25;i >= 0;i--){
int num = seg[i].query(1,1,n,l,r);
if(!num) continue;
seg[i].update(1,1,n,l,r,0);
seg[i].update(1,1,n,l + cur,l + cur + num - 1,1);
cur += num;
}
}
}
for(int i = 0;i < n;i++){
for(int j = 0;j < 26;j++){
if(seg[j].query(1,1,n,i + 1,i + 1)) {
s[i] = 'a' + j;
break;
}
}
}
printf("%s",s);
}