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;
    }
}
posted @ 2022-03-03 17:57  Bellala  阅读(145)  评论(0)    收藏  举报