1. 程式人生 > >校內集訓 miku set模擬冒泡排序 逆序對

校內集訓 miku set模擬冒泡排序 逆序對

冒泡排序 log urn iter 序列 swa 我們 pri esp

題意

  • 給你一個長為\(n\)的序列,進行\(m\)次操作,每次對一個區間進行排序,求最後的序列\((n <= 1500, m <= 1e6)\)

這道題目思維難度挺大的

對於一個序列,排序的本質就是消除裏面的所有逆序對

考慮冒泡排序的過程,每次也是交換\(a[i]>a[i+1]\)這個逆序對

這樣子交換最多有\(n^2\)

那麽我們可以用一個數據結構模擬冒泡排序交換逆序對這個過程

用一個\(set\)維護所有逆序對的位置

每次暴力刪除區間內所有逆序對

再把新產生的逆序對加入\(set\)

復雜度\(O((n^2+m)\log n)\)

Codes

#include <set>
#include <cstdio>

using namespace std;

const int N = 1500 + 10;

set<int> S;
set<int>::iterator it;

int a[N], n, q, L, R;

int main() {
    //freopen("miku.in", "r", stdin);
    //freopen("miku.out", "w", stdout);

    scanf("%d%d%d%d", &n, &q, &L, &R);
    for (int i = 1; i <= n; ++ i) 
        scanf("%d", &a[i]);
    for (int i = 1; i < n; ++ i) 
        if (a[i] > a[i + 1]) 
            S.insert(i);
    S.insert(n), a[n + 1] = 2e9;

    while (q --) {
        int l, r; scanf("%d%d", &l, &r);
        for (; *(it = S.lower_bound(l)) < r; S.erase(it ++)) {
            swap(a[*it], a[*it + 1]);
            if(a[*it - 1] > a[*it]) S.insert(*it - 1);
            if(a[*it + 1] > a[*it + 2]) S.insert(*it + 1);
        }
    }

    for (int i = L; i <= R; ++ i)
        printf("%d%c", a[i], i == R ? ‘\n‘ : ‘ ‘);

    return 0;
}

校內集訓 miku set模擬冒泡排序 逆序對