Daimayuan Online Judge 订单编号

本文介绍了一种解决订单编号可能重复的算法,通过使用有序集合(如C++中的set)来跟踪已使用的订单编号,按照时间顺序为每个新订单分配一个大于等于原订单编号且未被使用的最小整数作为新编号。具体实现中,利用set的lower_bound功能查找并更新编号区间,确保编号的唯一性。
摘要由CSDN通过智能技术生成

小缘开了一家公司,生意很好,每天都会收到很多订单,自动交易系统会自动给这些订单生成没有重复的订单编号。但是有一天,系统出现了未知的错误,导致当天的订单编号可能有重复的,这可把小缘急坏了。你可以帮助小缘按照规则给这些订单重新编号吗?

按照时间先后顺序给出 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值