小缘开了一家公司,生意很好,每天都会收到很多订单,自动交易系统会自动给这些订单生成没有重复的订单编号。但是有一天,系统出现了未知的错误,导致当天的订单编号可能有重复的,这可把小缘急坏了。你可以帮助小缘按照规则给这些订单重新编号吗?
按照时间先后顺序给出 NN 个正整数作为原订单编号,你需要按照规则依次赋予这些订单新的编号,对于任意一个订单,要找到大于等于其原订单编号且未被使用过的(没有被之前的订单作为新的订单编号)的最小整数,作为它的新订单编号。
例如: 原订单编号依次为1 2 3 1,则新订单编号应该为1 2 3 4 (前3个订单的原订单编号都没有使用过,所以用其原订单编号即可,对于第四个订单,原订单编号为1,而1, 2, 3都已经被使用过,所以新订单编号为4)。
输入格式
第一行输入一个整数 NN (1≤N≤5×105)(1≤N≤5×105)。
第二行输入 NN 个数 aiai (1≤ai≤109)(1≤ai≤109) 作为原订单编号。
输出格式
输出一行,包含 NN 个整数为新的订单编号。
样例输入1
6
2 3 4 1 1 1
样例输出1
2 3 4 1 5 6
样例输入2
3
1000000000 1000000000 1000000000
样例输出2
1000000000 1000000001 1000000002
样例输入3
6
4 5 1 2 1 1
样例输出3
4 5 1 2 3 6
思路:这是一个套路题,这个题相当于是一个无限更新的题,那么我们需要用固定的长度区间去来往里面添加元素,我们可以把单点操作变成区间查询。我们可以利用set的自动排序来找,但是插入区间时需要倒着插,因为正着插无法找到大于等于x的数,例如刚开始时只有一个区间,他就根本查不到大于等于x的区间。set用法:set排序遇到pair,lower_bound查的是set的first,不会查second,除非first相等才会按照second来排。查到的时候只需要观察是否在区间内即可,(如果区间的最小值大于等于x就直接输出x,如果区间最小值大于x就输出区间最小值)查到之后将该点去掉分成两个区间。插入pair时需要用insert,并且带上大括号{}。
完整代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
typedef vector<int> vi;
//#define int long long
#define fir first
#define sec second
#define all(x) (x).begin(), (x).end()
#define sz(x) (int)x.size()
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define repd(i, l, r) for (int i = l; i >= r; --i)
#define pb push_back
set<pair<int,int> >se;
void myinsert(int l,int r)
{
if(r<l)return;
se.insert({r,l});
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
se.insert({2e9,1});
rep(i,1,n)
{
int x;
cin>>x;
auto it=se.lower_bound({x,0});
if(it->sec <=x)
{
cout<<x<<" ";
myinsert(it->sec,x-1);
myinsert(x+1,it->fir);
se.erase(it);
}
else
{
cout<<it->sec<<" ";
myinsert(it->sec+1,it->fir);
se.erase(it);
}
}
return 0;
}