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;
}
}

浙公网安备 33010602011771号