专栏文章

[ABC392F] Insert

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqaswb5
此快照首次捕获于
2025/12/04 01:45
3 个月前
此快照最后确认于
2025/12/04 01:45
3 个月前
查看原文

前言

这次 ABC 为什么这么水啊。

正文

题目大意就是说给定一个序列 aa,依次将 11nnAA(初始为空)的第 aia_i 位插入,问最后的 AA 的排列是什么。
首先说一下一个暴力的做法,维护每一个数字 kk 出现的下标 pkp_k
考虑在每次插入一个数字 xx 的时候怎么做。显然,对于所有的 1i<x1 \le i < x,需满足 piaip_i \ge a_i,数字 ii 才能往后移动一位。
朴素这么做是 Θ(n2)\Theta(n^2) 的,考虑优化。
我们发现需要这么一个数据结构:
  1. 对于区间 [1,i][1,i],所有大于等于 xx 的数 +1+1
  2. 单点查询 ii
容易发现这个数据结构不好做的,考虑换思路。
正难则反,于是考虑反着来。
不难发现,我们可以先固定 AA 中的 nn 个位置,然后,依次模拟将数字插入“空位”的过程。
通俗的来说,对于每个数字 ii,我们只需找出当前第 aia_i 个空闲位置,把 ii 放进去即可。
具体而言,我们可以用树状数组实现。为了快速找到第 kk 个空位,我们钦定空位为 11,非空位为 00。这样,树状数组维护的前缀和就是单调的,可以使用二分查找。

Code

笨人写的 Θ(nlog2n)\Theta(n \log^2 n),常数较小可以通过,树状数组上二分即可达到 Θ(nlogn)\Theta(n \log n) 的优秀复杂度。
CPP
#include <bits/stdc++.h>
#ifdef LOCAL
    #include "debug.h"
#else
    #define debug(...) 42
#endif
#define mkp make_pair
#define pb emplace_back
#define endl "\n"
using namespace std;
using ll = long long;
int n,m,t,cnt=0;
const int maxn=1e5+10;
const double eps=1e-6;
struct BIT{
    int n;vector<int> brr;
    BIT(int range){n=range;brr.resize(n+1,0);}
    int lowbit(int x){return x&(-x);}
    inline void add(int x, int k){while(x<=n){brr[x]+=k;x+=lowbit(x);}}
    inline int query(int x){int ans=0;while(x!=0){ans+=brr[x];x-=lowbit(x);}return ans;}
    inline int queryRange(int l, int r){return query(r)-query(l-1);}
};
signed main(){
    cin.tie(nullptr)->sync_with_stdio(0);
    cin>>n;
    vector<int> a(n+1),ans(n+1,0);
    for(int i=1;i<=n;i++) cin>>a[i];
    BIT bit(n);
    for(int i=1;i<=n;i++) bit.add(i,1);
    auto chk=[&](int k){
        int lo=1,hi=n;
        while(lo<hi){
            int mid=(lo+hi)>>1;
            if(bit.query(mid)<k) lo=mid+1;
            else hi=mid;
        }
        return lo;
    };
    for(int i=n;i>=1;i--){
        int pos=chk(a[i]);
        ans[pos]=i;
        bit.add(pos,-1);
    }
    for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...