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 }

 

posted @ 2020-08-29 15:38  louis_11  阅读(182)  评论(0编辑  收藏  举报