給定一個由小寫字母組成的字符串$s$。html
有$m$次操做,每次操做給定$3$個參數$l,r,x$。c++
若是$x=1$,將$s[l]~s[r]$升序排序;算法
若是$x=0$,將$s[l]~s[r]$降序排序。ui
你須要求出最終序列。spa
第一行兩個整數$n,m$。
第二行一個字符串$s$。
接下來m行每行三個整數$l,r,x$。htm
一行一個字符串表示答案。blog
樣例輸入排序
5 2
cabcd
1 3 1
3 5 0字符串
樣例輸出get
abdcc
對於$40\%$的數據,$n,m\leqslant 1,000$。
對於$100\%$的數據,$n,m\leqslant 100,000$。
看到這道題,我就想到了:[BZOJ4552]:[Tjoi2016&Heoi2016]排序(桶排序)。
然而,那道題我使用桶排序卡過的,時限仍是$6,000ms$,因此我當場懵逼,線段樹是確定看出來了,可是不知道該怎麼操做……
打題必定要打正解挖~
$40\%$算法:
直接用$sort$搞就行了,重載一下運算符,我以爲我說的每一句都是廢話……
桶排一分也不能多拿(萬惡的出題人)。
時間複雜度:
$\Theta(m\times n)$(桶排序)。
$\Theta( m\times n\log n)$(快排)。
指望得分:$40$分。
$100\%$算法:
由於這道題串中只有26個字母,因此就好說多了,用線段樹維護區間內$a~z$的個數,每次修改拆成26個修改就好了。
時間複雜度:$\Theta(26\times m\times \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++