string
题目描述:
给定一个由小写字母组成的字符串$s$。
有$m$次操作,每次操作给定$3$个参数$l,r,x$。
如果$x$ $=$ $1$,将$s[l]$ $~$ $s[r]$升序排序;
如果$x$ $=$ $0$,将$s[l]$ $~$ $s[r]$降序排序。
你需要求出最终序列。
输入格式:
第一行两个整数$n,m$。
第二行一个字符串$s$。
接下来$m$行每行三个整数$x,l,r$。
输出格式:
一行一个字符串表示答案。
输入样例:
5 2 cabcd 1 3 1 3 5 0
输出样例:
abdcc
数据范围:
对于$100\%$的数据,$n,m$ $≤$ $100000$。
思路:
因为数据达到了$1e5$,所以考虑$m$ $log$ $n$的复杂度(可能有常数)。
观察到字符串只由小写字母组成,所以考虑一种类似于桶排的思想。
首先考虑一个$01$序列,如果将它排序只需要考虑$0$的数量和$1$的数量即可。
如果把字符串看成一个由$1$ $~$ $26$构成的序列,并现将$1$看作$0$,其余看作$1$,将这个字符串排序就会变成一个前面是$0$,后面是$1$的序列,因为是把$1$转化成$0$的,所以序列中的$0$就是$1$;再将$1$和$2$看作$0$,其余看作$1$,再排序就会变成一个前面是$0$,后面是$1$的序列,因为$1$的位置已经确定了,所以剩下的$0$的位置就是$2$了;以此类推。
考虑用线段树维护这个$01$区间中$0$和$1$的数量,依次为$1,1、2,1、2、3,1、2、3、4……$做线段树,然后如上记录答案。
代码:
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int n, m, q[100010], sum[100010], l[100010], r[100010], x[100010], ans[100010]; 5 char s[100010]; 6 struct Tree {int l, r, val, lazy;}tree[800010]; 7 void build(int u, int l, int r) 8 { 9 int mid = (l + r) >> 1; 10 tree[u].l = l, tree[u].r = r, tree[u].lazy = -1; 11 if(l == r) {tree[u].val = sum[l]; return;} 12 build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); 13 tree[u].val = tree[u << 1].val + tree[u << 1 | 1].val; 14 return; 15 } 16 void pushdown(int u) 17 { 18 if(!(~tree[u].lazy)) return; 19 int mid = (tree[u].l + tree[u].r) >> 1; 20 tree[u << 1].lazy = tree[u << 1 | 1].lazy = tree[u].lazy; 21 tree[u << 1].val = tree[u << 1].lazy * (mid - tree[u].l + 1), tree[u << 1 | 1].val = tree[u << 1 | 1].lazy * (tree[u].r - mid); 22 tree[u].lazy = -1; 23 return; 24 } 25 void change(int u, int l, int r, int x) 26 { 27 if(tree[u].l > r || tree[u].r < l) return; 28 if(tree[u].l >= l && tree[u].r <= r) {tree[u].lazy = x, tree[u].val = x * (tree[u].r - tree[u].l + 1); return;} 29 pushdown(u); 30 change(u << 1, l, r, x), change(u << 1 | 1, l, r, x); 31 tree[u].val = tree[u << 1].val + tree[u << 1 | 1].val; 32 return; 33 } 34 int query(int u, int l, int r) 35 { 36 if(tree[u].l > r || tree[u].r < l) return 0; 37 if(tree[u].l >= l && tree[u].r <= r) return tree[u].val; 38 pushdown(u); 39 return query(u << 1, l, r) + query(u << 1 | 1, l, r); 40 } 41 void solve(int num) 42 { 43 for(int i = 1; i <= n; ++i) sum[i] = (q[i] > num ? 1 : 0); 44 build(1, 1, n); 45 for(int i = 1; i <= m; ++i) 46 { 47 int cnt = query(1, l[i], r[i]); 48 if(x[i] == 1) change(1, l[i], r[i] - cnt, 0), change(1, r[i] - cnt + 1, r[i], 1); 49 else change(1, l[i], l[i] + cnt - 1, 1), change(1, l[i] + cnt, r[i], 0); 50 } 51 for(int i = 1; i <= n; ++i) 52 { 53 int cnt = query(1, i, i); 54 if(ans[i]) continue; 55 if(!cnt) ans[i] = num; 56 } 57 return; 58 } 59 int main() 60 { 61 scanf("%d %d %s", &n, &m, s + 1); 62 for(int i = 1; i <= n; ++i) q[i] = (int)s[i] - 'a' + 1; 63 for(int i = 1; i <= m; ++i) scanf("%d %d %d", &l[i], &r[i], &x[i]); 64 for(int i = 1; i <= 26; ++i) solve(i); 65 for(int i = 1; i <= n; ++i) printf("%c", (char)(ans[i] + 'a' - 1)); 66 return 0; 67 }