Codeforces 558E - A Simple Task

算法总在某个范围不大的维度上直接暴力。

这次的维度是字符集的大小,总共只有26个字符,所以直接用counting sort,其实这货也算是桶排吧,但是要能用这样的排序还有一个条件是不区分原子吧。
每次操作在制定的区间上,先查询出每个字符分别有多少个,然后按大小排列好。查询和排列用线段树维护,所以每次操作都是 O(logn) 的复杂度。最后从头到尾查一次就好了。
之前用Python写了这题,怎么都过不了,不开心。

#include <iostream>

using namespace std;

const int MAX_SIZE = 1e5 + 10;

#define m ((l + r) / 2)
#define lchild l, m, index * 2
#define rchild m + 1, r, index * 2 + 1
#define covered x <= l && r <= y
#define interact(l, r) x <= r && l <= y

class SegmentTree {
private:
    int L, R, sum[MAX_SIZE << 2], lazy[MAX_SIZE << 2];

    void set_lazy(int value, int l, int r, int index) {
        sum[index] = value * (r - l + 1);
        lazy[index] = value;
    }

    void push_down(int l, int r, int index) {
        if (l != r && lazy[index] != -1) {
            set_lazy(lazy[index], lchild);
            set_lazy(lazy[index], rchild);
            lazy[index] = -1;
        }
    }

    void pull_up(int l, int r, int index) {
        if (l != r) {
            sum[index] = sum[index * 2] + sum[index * 2 + 1];
        }
    }

    int query(int x, int y, int l, int r, int index) {
        if (covered) {
            return sum[index];
        } else {
            push_down(l, r, index);
            int ans = 0;
            if (interact(l, m)) {
                ans += query(x, y, lchild);
            }
            if (interact(m + 1, r)) {
                ans += query(x, y, rchild);
            }
            return ans;
        }
    }

    void update(int x, int y, int value, int l, int r, int index) {
        if (covered) {
            set_lazy(value, l, r, index);
        }
        else {
            push_down(l, r, index);
            if (interact(l, m)) {
                update(x, y, value, lchild);
            }
            if (interact(m + 1, r)) {
                update(x, y, value, rchild);
            }
            pull_up(l, r, index);
        }
    }
public:
    void clear(int l, int r) {
        L = l;
        R = r;
        fill(sum, sum + MAX_SIZE, 0);
        fill(lazy, lazy + MAX_SIZE, -1);
    }

    int query(int x, int y) {
        return query(x, y, L, R, 1);
    }

    void update(int x, int y, int value) {
        update(x, y, value, L, R, 1);
    }
} trees[26];

string s;
int n, q, a, b, k, cnt[26];

int main(int argc, char const *argv[]) {
    // freopen("miao.txt", "r", stdin);

    while (cin >> n >> q) {
        for (auto i = 0; i < 26; ++i) {
            trees[i].clear(1, n);
        }

        cin >> s;
        for (auto i = 0; i < s.length(); ++i) {
            trees[s[i] - 'a'].update(i + 1, i + 1, 1);
        }

        for (auto _ = 0; q > _; _++) {
            cin >> a >> b >> k;
            fill(cnt, cnt + 26, 0);
            for (auto i = 0; i < 26; ++i) {
                cnt[i] = trees[i].query(a, b);
            }
            if (k == 1) {
                auto current = a;
                for (auto i = 0; i < 26; ++i) {
                    trees[i].update(a, b, 0);
                    trees[i].update(current, current + cnt[i] - 1, 1);
                    current += cnt[i];
                }
            } else {
                auto current = a;
                for (auto i = 25; 0 <= i; --i) {
                    trees[i].update(a, b, 0);
                    trees[i].update(current, current + cnt[i] - 1, 1);
                    current += cnt[i];
                }
            }
        }
        for (auto i = 1; i <= n; ++i) {
            for (auto j = 0; j < 26; ++j) {
                if (trees[j].query(i, i)) {
                    cout << (char)(j + 'a');
                    break;
                }
            }
        }
        cout << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值