Codeforces #452 Div2 F

#452 Div2 F

题意

给出一个字符串, m 次操作,每次删除区间 \([l,r]\) 之间的字符 \(c\) ,输出最后得到的字符串。

分析

通过树状数组和二分,我们可以把给定的区间对应到在起始字符串上的区间。
然后暴力去删字符即可(因为最多只会删掉等同于字符串长度的字符个数),总共只有 62 种字符,set 维护下位置。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 10;
int n, m, f[N];
void update(int x) {
    for(int i = x; i < N; i += i & -i) f[i]--;
}
int query(int x) {
    int s = 0;
    for(int i = x; i; i -= i & -i) s += f[i];
    return s;
}
int fd(int x) {
    int l = 1, r = n, mid;
    while(l < r) {
        mid = l + r >> 1;
        if(query(mid) < x) l = mid + 1;
        else r = mid;
    }
    return l;
}
char s[N];
set<int> S[150];
char ans[N];
int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", s + 1);
    for(int i = 1; i <= n; i++) {
        S[s[i]].insert(i);
        f[i + (i & -i)] += ++f[i];
    }
    while(m--) {
        char c[2];
        int l, r;
        scanf("%d%d%s", &l, &r, c);
        l = fd(l);
        r = fd(r);
        auto it = S[c[0]].lower_bound(l);
        while(it != S[c[0]].end() && *it <= r) {
            update(*it);
            auto itt = it;
            it++;
            S[c[0]].erase(itt);
        }
    }
    for(int i = 0; i < 150; i++) {
        for(int j : S[i]) ans[j] = i;
    }
    for(int i = 1; i <= n; i++) {
        if(ans[i]) cout << ans[i];
    }
    return 0;
}
posted @ 2017-12-19 23:18  ftae  阅读(104)  评论(0编辑  收藏  举报