Codeforces 588E. A Simple Task (线段树+计数排序思想)

题目链接:http://codeforces.com/contest/558/problem/E

题意:有一串字符串,有两个操作:1操作是将l到r的字符串升序排序,0操作是降序排序。

题解:建立26棵线段树,类似计数排序思想。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int N = 1e5 + 5;
  4 struct SegTree {
  5     int lazy[27], sum[27], l, r;
  6 }T[N << 2];
  7 int a[27][N];
  8 
  9 void pushup(int p, int c) {
 10     T[p].sum[c] = T[p << 1].sum[c] + T[(p << 1)|1].sum[c];
 11 }
 12 
 13 void pushdown(int p, int c) {
 14     if(T[p].lazy[c] != -1) {
 15         T[p << 1].sum[c] = T[p].lazy[c]*(T[p << 1].r - T[p << 1].l + 1);
 16         T[(p << 1)|1].sum[c] = T[p].lazy[c]*(T[(p << 1)|1].r - T[(p << 1)|1].l + 1);
 17         T[p << 1].lazy[c] = T[(p << 1)|1].lazy[c] = T[p].lazy[c];
 18         T[p].lazy[c] = -1;
 19     }
 20 }
 21 
 22 void build(int p, int c, int l, int r) {
 23     int mid = (l + r) >> 1;
 24     T[p].l = l, T[p].r = r, T[p].lazy[c] = -1;
 25     if(l == r) {
 26         T[p].sum[c] = a[c][l];
 27         return ;
 28     }
 29     build(p << 1, c, l, mid);
 30     build((p << 1)|1, c, mid + 1, r);
 31     pushup(p, c);
 32 }
 33 
 34 int query(int p, int c, int l, int r) {
 35     int mid = (T[p].l + T[p].r) >> 1;
 36     if(T[p].l == l && T[p].r == r) {
 37         return T[p].sum[c];
 38     }
 39     pushdown(p, c);
 40     if(r <= mid) {
 41         return query(p << 1, c, l, r);
 42     } else if(l > mid) {
 43         return query((p << 1)|1, c, l, r);
 44     } else {
 45         return query(p << 1, c, l, mid) + query((p << 1)|1, c, mid + 1, r);
 46     }
 47     pushup(p, c);
 48 }
 49 
 50 void update(int p, int c, int l, int r, int val) {
 51     int mid = (T[p].l + T[p].r) >> 1;
 52     if(T[p].l == l && T[p].r == r) {
 53         T[p].lazy[c] = val;
 54         T[p].sum[c] = val * (r - l + 1);
 55         return ;
 56     }
 57     pushdown(p, c);
 58     if(r <= mid) {
 59         update(p << 1, c, l, r, val);
 60     } else if(l > mid) {
 61         update((p << 1)|1, c, l, r, val);
 62     } else {
 63         update(p << 1, c, l, mid, val), update((p << 1)|1, c, mid + 1, r, val);
 64     }
 65     pushup(p, c);
 66 }
 67 char str[N];
 68 
 69 int main()
 70 {
 71     int n, m;
 72     scanf("%d %d", &n, &m);
 73     scanf("%s", str);
 74     for(int i = 0; i < n; ++i) {
 75         a[str[i] - 'a'][i + 1] = 1;
 76     }
 77     for(int i = 0; i < 26; ++i) {
 78         build(1, i, 1, n);
 79     }
 80     while(m--) {
 81         int l, r, c;
 82         scanf("%d %d %d", &l, &r, &c);
 83         if(c) {
 84             int x = l, y = r;
 85             for(int i = 0; i < 26; ++i) {
 86                 if(x > y)
 87                     break;
 88                 int num = query(1, i, l, r);
 89                 if(!num)
 90                     continue;
 91                 update(1, i, l, r, 0);
 92                 update(1, i, x, x + num - 1, 1);
 93                 x = x + num;
 94             }
 95         } else {
 96             int x = l, y = r;
 97             for(int i = 25; i >= 0; --i) {
 98                if(x > y)
 99                     break;
100                 int num = query(1, i, l, r);
101                 if(!num)
102                     continue;
103                 update(1, i, l, r, 0);
104                 update(1, i, x, x + num - 1, 1);
105                 x = x + num;
106             }
107         }
108     }
109     for(int i = 1; i <= n; ++i) {
110         for(int j = 0; j < 26; ++j) {
111             if(query(1, j, i, i)) {
112                 putchar(char(j + 'a'));
113                 break;
114             }
115         }
116     }
117     putchar('\n');
118     return 0;
119 }

 

转载于:https://www.cnblogs.com/Recoder/p/5931255.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值