题目描述
给定一个由小写字母组成的字符串$s$。
有$m$次操作,每次操作给定$3$个参数$l,r,x$。
如果$x=1$,将$s[l]~s[r]$升序排序;
如果$x=0$,将$s[l]~s[r]$降序排序。
你需要求出最终序列。
输入格式
第一行两个整数$n,m$。
第二行一个字符串$s$。
接下来m行每行三个整数$l,r,x$。
输出格式
一行一个字符串表示答案。
样例
样例输入
5 2
cabcd
1 3 1
3 5 0
样例输出
abdcc
数据范围与提示
对于$40\%$的数据,$n,mleqslant 1,000$。
对于$100\%$的数据,$n,mleqslant 100,000$。
题解
看到这道题,我就想到了:[BZOJ4552]:[Tjoi2016&Heoi2016]排序(桶排序)。
然而,那道题我使用桶排序卡过的,时限还是$6,000ms$,所以我当场懵逼,线段树是肯定看出来了,但是不知道该怎么操作……
打题一定要打正解挖~
$40\%$算法:
直接用$sort$搞就好了,重载一下运算符,我觉得我说的每一句都是废话……
桶排一分也不能多拿(万恶的出题人)。
时间复杂度:
$Theta(m imes n)$(桶排序)。
$Theta( m imes nlog n)$(快排)。
期望得分:$40$分。
$100\%$算法:
因为这道题串中只有26个字母,所以就好说多了,用线段树维护区间内$a~z$的个数,每次修改拆成26个修改就行了。
时间复杂度:$Theta(26 imes m imes log n)$。
期望得分:$100$分。
代码时刻
$40\%$算法:
#include<bits/stdc++.h> using namespace std; int n,m,l,r; bool x; int a[100001]; char ch[100001]; int t[50]; int st,ed; void change1() { register int maxn=0,minn=20020923,lft=l; for(int i=l;i<=r;i++) { t[a[i]]++; maxn=max(maxn,a[i]); minn=min(minn,a[i]); } for(register int i=minn;i<=maxn;i++) while(t[i]) { a[lft++]=i; t[i]--; } } void change2() { int maxn=0,minn=20020923,lft=l; for(register int i=l;i<=r;i++) { t[a[i]]++; maxn=max(maxn,a[i]); minn=min(minn,a[i]); } for(register int i=maxn;i>=minn;i--) while(t[i]) { a[lft++]=i; t[i]--; } } int main() { st=clock(); scanf("%d%d%s",&n,&m,ch+1); for(register int i=1;i<=n;i++) a[i]=ch[i]-'a'+1; while(m--) { scanf("%d%d%d",&l,&r,&x); if(x)change1(); else change2(); } for(register int i=1;i<=n;i++) printf("%c",(char)a[i]+'a'-1); return 0; }
$100\%$算法:
#include<bits/stdc++.h> #define L(x) x<<1 #define R(x) x<<1|1 using namespace std; int n,m; char ch[100001]; int tr[400001]; int flag[30]; void pushup(int x){if(tr[L(x)]==tr[R(x)])tr[x]=tr[L(x)];} void pushdown1(int x){if(tr[x])tr[L(x)]=tr[R(x)]=tr[x];} void pushdown2(int x){if(tr[x])tr[L(x)]=tr[R(x)]=tr[x];tr[x]=0;} void build(int x,int l,int r) { if(l==r){tr[x]=ch[l]-'a'+1;return;} int mid=(l+r)>>1; build(L(x),l,mid); build(R(x),mid+1,r); pushup(x); } void ask(int x,int l,int r,int L,int R) { if(r<L||R<l)return; if(L<=l&&r<=R&&tr[x]){flag[tr[x]]+=r-l+1;return;} int mid=(l+r)>>1; pushdown1(x); ask(L(x),l,mid,L,R); ask(R(x),mid+1,r,L,R); } void change(int x,int l,int r,int L,int R,int v) { if(r<L||R<l)return; if((L<=l&&r<=R)||tr[x]==v){tr[x]=v;return;} int mid=(l+r)>>1; pushdown2(x); change(L(x),l,mid,L,R,v); change(R(x),mid+1,r,L,R,v); pushup(x); } void print(int x,int l,int r) { if(tr[x]){for(int i=l;i<=r;i++)printf("%c",(char)tr[x]+'a'-1);return;} int mid=(l+r)>>1; print(L(x),l,mid); print(R(x),mid+1,r); } int main() { scanf("%d%d%s",&n,&m,ch+1); build(1,1,n); while(m--) { int l,r,x; scanf("%d%d%d",&l,&r,&x); memset(flag,0,sizeof(flag)); ask(1,1,n,l,r); if(x)for(int i=1;i<=26;i++){change(1,1,n,l,l+flag[i]-1,i);l+=flag[i];} else for(int i=26;i>=1;i--){change(1,1,n,l,l+flag[i]-1,i);l+=flag[i];} } print(1,1,n); return 0; }
rp++