Description
给定一个由小写字母组成的字符串 s。有 m 次操作,每次操作给 定 3 个参数 l,r,x。如果 x=1,将 s[l]~s[r]升序排序;如果 x=0,将 s[l]~s[r] 降序排序。你需要求出最终序列。
Input
第一行两个整数 n,m。第二行一个字符串 s。接下来 m 行每行三 个整数 l,r,x。
Output
一行一个字符串表示答案。
Sample Input
5 2
cabcd
1 3 1
3 5 0
Sample Output
abdcc
Data Constraint
对于 40%的数据,n,m<=1000。
对于 100%的数据,n,m<=100000
思路
由于只有小写字母,也就说元素只有26种,所以我们考虑用线段树维护区间内有多少字母【a..z】
对于每个修改操作,先统计区间有多少字母,在逐个加入线段树
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+77;
struct tree
{
int l,r,v;
}tr[maxn*3];
char st[maxn];
int n,m,f[29];
void build(int l,int r,int x)
{
tr[x].l=l; tr[x].r=r;
if(l==r)
{
tr[x].v=st[l]-'a'+1; return;
}
int mid=(l+r)>>1;
build(l,mid,x*2); build(mid+1,r,x*2+1);
if(tr[x*2].v==tr[x*2+1].v) tr[x].v=tr[x*2].v;
}
void get_f(int l,int r,int x)
{
if(tr[x].l>=l&&tr[x].r<=r&&tr[x].v)
{
f[tr[x].v]+=tr[x].r-tr[x].l+1; return;
}
if(tr[x].v) tr[x*2].v=tr[x].v,tr[x*2+1].v=tr[x].v;
int mid=(tr[x].l+tr[x].r)>>1;
if(mid>=l) get_f(l,r,x*2);
if(mid<r) get_f(l,r,x*2+1);
}
void work(int l,int r,int u,int x)
{
if(tr[u].l>=l&&tr[u].r<=r||tr[u].v==x)
{
tr[u].v=x; return;
}
if(tr[u].v) tr[u*2].v=tr[u].v,tr[u*2+1].v=tr[u].v,tr[u].v=0;
int mid=(tr[u].l+tr[u].r)/2;
if(l<=mid) work(l,r,u*2,x);
if(mid<r) work(l,r,u*2+1,x);
if(tr[u*2].v==tr[u*2+1].v) tr[u].v=tr[u*2].v;
}
void print(int x)
{
if(tr[x].v)
{
for(int i=tr[x].l; i<=tr[x].r; i++) printf("%c",tr[x].v+'a'-1); return;
}
print(x*2),print(x*2+1);
}
int main()
{
freopen("string.in","r",stdin); freopen("string.out","w",stdout);
scanf("%d%d\n",&n,&m);
scanf("%s",st+1);
build(1,n,1);
for(int i=1; i<=m; i++)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
memset(f,0,sizeof(f));
get_f(l,r,1);
if(x)
{
for(int j=1; j<=26; j++) if(f[j]) work(l,l+f[j]-1,1,j),l+=f[j];
}else
{
for(int j=26; j>=1; j--) if(f[j]) work(l,l+f[j]-1,1,j),l+=f[j];
}
}
print(1);
}