1. 程式人生 > 其它 >daimayuan465. 訂單編號(set/並查集)

daimayuan465. 訂單編號(set/並查集)

題意:

給定陣列 \(a[]\)。構造新陣列 \(b[]\),要求 \(b_i\ge a_i\)\(b_i\neq b_{1\sim i-1}\),且 \(b_i\) 儘量小。輸出新陣列。

\(1\le n \le 5e5,1\le a_i \le 1e9\)

思路:

法一:set存區間,二分

set存所有未使用的閉區間的兩個端點,按右端點從小到大排序。對於每個數 x,二分找右端點大於等於 x 的未使用區間,看要不要把區間裂成兩個

set存用過的區間也能做,但是要討論區間的合併,特別麻煩。

int n; set<PII> S;
void ins(int l, int r) //防止l>r
{
    if(l <= r) S.insert({r,l});
}
main()
{
    iofast;
    S.insert({2e9,0});
    cin >> n; while(n--)
    {
        int x; cin >> x;
        auto it = S.lower_bound({x,0});
        if(it->se <= x) ins(x+1,it->fi), ins(it->se,x-1);
        else x = it->se, ins(x+1,it->fi);
        S.erase(it), cout << x << ' ';
    }
}

法二:雜湊+並查集(慢一點)

p[x] 存 x 所在的集合的右邊第一個未使用位置。

unordered_map<int, int> p;
int get(int x) {
    return (!p[x] ? x : (p[x] = get(p[x])) );
}

main()
{
    iofast;
    int n; cin >> n; while(n--)
    {
        int x; cin >> x;
        x = get(x);
        cout << x << ' ';
        p[x] = x + 1;
    }
}