思路:
我们不妨设26个线段树表示当前节点上有没有这个字母。
然后在做时首先把每个字母在区间的个数选出来
然后从小到大(或从大到小)依次插入
c o d e code code
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n, m;
char c[100010];
int tmp[27], f[400010];
struct node
{
int x;
}a[27][4000100];
void down(int k, int l, int r)
{
if(f[k]!=-1&&l!=r)
{
int mid=l+r>>1;
f[k*2]=f[k*2+1]=f[k];
for(int i=0; i<26; i++)
a[i][k*2].x=0;
a[f[k]][k*2].x=mid-l+1;
for(int i=0; i<26; i++)
a[i][k*2+1].x=0;
a[f[k]][k*2+1].x=r-mid;
}
f[k]=-1;
}
void build(int k, int l, int r)
{
if(l==r)
{
a[c[l]-'a'][k].x=1;
return;
}
int mid=l+r>>1;
build(k*2, l, mid);
build(k*2+1, mid+1, r);
for(int i=0; i<26; i++)
a[i][k].x=a[i][k*2].x+a[i][k*2+1].x;
}
int get_num(int k, int l, int r, int x, int y, int z)
{
if(x<=l&&r<=y)
return a[z][k].x;
down(k, l, r);
int mid=l+r>>1, re=0;
if(x<=mid)
re+=get_num(k*2, l, mid, x, y, z);
if(y>mid)
re+=get_num(k*2+1, mid+1, r, x, y, z);
return re;
}
void change_num(int k, int l, int r, int x, int y, int z)
{
if(x<=l&&r<=y)
{
for(int i=0; i<26; i++)
a[i][k].x=0;
a[z][k].x=r-l+1;
f[k]=z;
return;
}
down(k, l, r);
int mid=l+r>>1;
if(x<=mid)
change_num(k*2, l, mid, x, y, z);
if(y>mid)
change_num(k*2+1, mid+1, r, x, y, z);
for(int i=0; i<26; i++)
a[i][k].x=a[i][k*2].x+a[i][k*2+1].x;
}
void Zi_O(int k, int l, int r)
{
if(l==r)
{
for(int i=0; i<26; i++)
if(a[i][k].x!=0)
{
printf("%c", i+'a');
return;
}
}
down(k, l, r);
int mid=l+r>>1;
Zi_O(k*2, l, mid);
Zi_O(k*2+1, mid+1, r);
}
int main()
{
memset(f, -1, sizeof(f));
scanf("%d%d", &n, &m);
scanf("%s", c+1);
build(1, 1, n);
while(m--)
{
int x, l, r;
scanf("%d%d%d", &l, &r, &x);
for(int i=0; i<26; i++)
tmp[i]=get_num(1, 1, n, l, r, i);
if(x==1)
{
int cnt=l;
for(int i=0; i<26; i++)
if(tmp[i])
{
change_num(1, 1, n, cnt, cnt+tmp[i]-1, i);
cnt+=tmp[i];
if(cnt>r)
break;
}
}
else
{
int cnt=l;
for(int i=25; i>=0; i--)
if(tmp[i])
{
change_num(1, 1, n, cnt, cnt+tmp[i]-1, i);
cnt+=tmp[i];
if(cnt>r)
break;
}
}
}
Zi_O(1, 1, n);
return 0;
}