給定一個由小寫字母組成的字符串\(S\)。有\(m\)次操做,每次操做給定3個參數\(l\),\(r\),\(x\) 。若是\(x=1\),將\(Sl∼Sr\)升序排序;若是\(x=0\),將\(Sl∼Sr\)降序排序。你須要求出最終序列。ios
第一行兩個整數 \(n\),\(m\)。第二行一個字符串\(S\)。接下來\(m\)行每行三個整數\(x\),\(l\),\(r\)。數組
一行一個字符串表示答案。優化
5 2 cabcd 1 3 1 3 5 0
abdcc
對於\(40%\)的數據,\(n,m≤1000\)。
對於\(100%\)的數據,\(n,m≤100000\)。ui
本題的數據範圍表示確定不能每次操做都進行一排序(\(O(m\times nlog(n))\))。
鑑於這個是區間問題,咱們能夠想到線段樹。再看因爲字符只有26種,就能夠想桶排序進行優化。每次排序的本質其實就是把第\(i\)個數移動到他該在的位置上面(至關於把他該在的區間修改成他的值)。因而咱們開一個數組\(cnt_{u,i}\)表示線段樹節點\(u\)上字符\(i\)出現次數。每次排序時候能夠根據這個進行區間修改(同時還要維護這個數組)。spa
#include <iostream> #include <cstring> #include <cstdio> #define lc(x) ((x) << 1) #define rc(x) (((x) << 1) | 1) using namespace std; const int N = 1e5 + 16; const int M = N * 4; int n, m; int cnt[M][28], tag[M]; char str[N]; void Build(int u, int l, int r) { if (l == r) { cnt[u][str[l] - 'a' + 1] = 1; return; } int mid = l + r >> 1; Build(lc(u), l, mid); Build(rc(u), mid + 1, r); for (int i = 1; i <= 26; i++) //Pushup cnt[u][i] = cnt[lc(u)][i] + cnt[rc(u)][i]; } inline void SetTag(int u, int l, int r, int val) { tag[u] = val; for (int i = 1; i <= 26; i++) cnt[u][i] = 0; cnt[u][val] = r - l + 1; } inline void Pushdown(int u, int l, int r) { if (tag[u]) { int mid = l + r >> 1; SetTag(lc(u), l, mid, tag[u]); SetTag(rc(u), mid + 1, r, tag[u]); tag[u] = 0; } } void Modify(int u, int l, int r, int x, int y, int val) //把x-y區間的值修改成val { if (r < x || l > y) return; if (x <= l && r <= y) { SetTag(u, l, r, val); return; } Pushdown(u, l, r); int mid = l + r >> 1; Modify(lc(u), l, mid, x, y, val); Modify(rc(u), mid + 1, r, x, y, val); for (int i = 1; i <= 26; i++) //Pushup cnt[u][i] = cnt[lc(u)][i] + cnt[rc(u)][i]; } int ret[28]; //承接Query的返回值 void Query(int u, int l, int r, int x, int y) //詢問l-r之間的各字母出現頻率 { if (r < x || l > y) return; if (x <= l && r <= y) { for (int i = 1; i <= 26; i++) ret[i] += cnt[u][i]; return; } Pushdown(u, l, r); int mid = l + r >> 1; Query(lc(u), l, mid, x, y); Query(rc(u), mid + 1, r, x, y); } char AnsStr[N]; void PrintAns(int u, int l, int r) { if (l == r) { for (int i = 1; i <= n; i++) if (cnt[u][i]) { AnsStr[l] = i + 'a' - 1; break; } return; } Pushdown(u, l, r); int mid = l + r >> 1; PrintAns(lc(u), l, mid); PrintAns(rc(u), mid + 1, r); } int main() { scanf(" %d %d", &n, &m); scanf(" %s", str + 1); Build(1, 1, n); while (m--) { int l, r, opt; scanf(" %d %d %d", &l, &r, &opt); memset(ret, 0, sizeof ret); Query(1, 1, n, l, r); if (opt == 1) //順序排序 { for (int i = 1; i <= 26; i++) { if (ret[i]) { Modify(1, 1, n, l, l + ret[i] - 1, i); //把i號字母放在前面 l += ret[i]; //移動到i號字母以後 } } } else { for (int i = 26; i >= 1; i--) { if (ret[i]) { Modify(1, 1, n, l, l + ret[i] - 1, i); l += ret[i]; } } } } PrintAns(1, 1, n); printf("%s", AnsStr + 1); return 0; }