Mybatis學習
阿新 • • 發佈:2020-07-31
string( \(\star\star \))
- 時限:\(1s\) 記憶體:\(256M\)
Descrption
- 給定一個由小寫字母組成的字串 \(s\)。有 \(m\) 次操作,每次操作給定 \(3\) 個引數 \(l,r,x\)。如果 \(x=1\),將 \(s[l]\sim s[r]\) 升序排序;如果 \(x=0\),將 \(s[l]~s[r]\) 降序排序。你需要求出最終序列。
Input
- 第一行兩個整數 \(n,m\),表示字串長度為 \(n\),有 \(m\) 次操作。
- 第二行一個字串 \(s\)。
- 接下來 \(m\) 行每行三個整數 \(l,r,x\)。
Output
- 一行一個字串表示答案。
Sample Input
5 2
cabcd
1 3 1
3 5 0
Sample Output
abdcc
Hint
- 對於 \(40\%\) 的資料,\(n,m<=1000\)。
- 對於 \(100\%\) 的資料,\(n,m<=100000\)。
- 來源:
分析
- 因為字串全是小寫字母,所以不同的字元最多隻有 \(26\) 個,我們可以用 \(1\sim 26\) 代替。可以建一棵線段樹,把各個葉子節點就是對應字母的值。
- 對於區間排序,實際上我們不需要真的排序,只要知道區間內有多少個字元,每個字元有多少,再逐一賦值即可。對於一個節點,如果其兩個子節點的數值相同,那麼它自己也附上相同的值。
- 修改時,如果一個區間均是同一個值,不需要遞迴到葉子,可以向類似的 \(lazy\) 標記一樣進行處理,如果區間不完全重合,那麼就要類似 \(lazy\) 標記一樣,先 \(pushdown\)
- 對於每一次操作,求其區間內各個字母的次數,如果升序就從 \(a\sim z\) ,降序就從 \(z\sim a\) 迴圈,依次替換線段樹中的位置。
Code
#include <bits/stdc++.h> const int maxn=1e5+7; struct tree{ int l,r,v; }a[maxn<<2]; char st[maxn]; int n,m,f[29]; void Build(int l,int r,int rt){ a[rt].l=l; a[rt].r=r; if(l==r){ a[rt].v=st[l]-'a'+1; return; } int mid=(l+r)>>1; Build(l,mid,rt<<1); Build(mid+1,r,rt<<1|1); if(a[rt<<1].v==a[rt<<1|1].v)//如果左右子樹字母相同則更新父區間 a[rt].v=a[rt<<1].v; } void get_f(int l,int r,int rt){//查詢區間l~r 出現的字母即其個數 if(a[rt].l>=l && a[rt].r<=r && a[rt].v){//a[rt].v!=0才表示區間內字元一樣 f[a[rt].v]+=a[rt].r-a[rt].l+1; return;//f[i]:表示字母i的個數 } if(a[rt].v)//類似的pushdown操作 a[rt<<1].v=a[rt<<1|1].v=a[rt].v; int mid=(a[rt].l+a[rt].r)>>1; if(mid>=l) get_f(l,r,rt<<1); if(mid<r) get_f(l,r,rt<<1|1); } void Work(int l,int r,int rt,int x){//把區間[l,r]全部賦值為x if(a[rt].l>=l&&a[rt].r<=r||a[rt].v==x){ a[rt].v=x; return; } if(a[rt].v){//類似pushdown a[rt<<1].v=a[rt<<1|1].v=a[rt].v; a[rt].v=0;//rt未包含在內說明會有部分不同 } int mid=(a[rt].l+a[rt].r)/2; if(l<=mid) Work(l,r,rt<<1,x); if(mid<r) Work(l,r,rt<<1|1,x); if(a[rt<<1].v==a[rt<<1|1].v)//左右子區間元素相同,rt區間也是同一個字母 a[rt].v=a[rt<<1].v; } void Print(int x){ if(a[x].v){ for(int i=a[x].l; i<=a[x].r; i++) printf("%c",a[x].v+'a'-1); return; } Print(x<<1),Print(x<<1|1); } void Solve(){ scanf("%d%d",&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); } int main(){ Solve(); return 0; }