前置芝士:线段树
因为题目给的信息 S i S_{i} Si 是小于等于第 i i i 位身高的人数量,也就是第 i i i 位人在前 i i i 个人中身高位第 S i + 1 S_i + 1 Si+1 位(从矮到高),为了排除后面人对操作的干扰,我们从后往前扫,在一段有序身高序列中找到身高第 S i + 1 S_i + 1 Si+1 小,再把他删掉就好了。
线段树或平衡树都可以实现,笔者用的是码量小又简单的线段树。
先把身高从小到大排序,建树、查询的时候以
s
i
z
e
size
size 为关键词查找,每次询问顺便将底部的
s
i
z
e
size
size 设为 1,并不断
u
p
d
a
t
e
update
update 就可以了。
详情请见代码 − − − > ---> −−−>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,w=0;char ch=getchar();
while (!isdigit(ch))w|=ch=='-',ch=getchar();
while (isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return w?-x:x;
}
struct node{
int val, size;
}a[5000005];
int n, b[100005], c[100005], ans[100005];
inline int ls(int p){
return p << 1;
}
inline int rs(int p){
return p << 1 | 1;
}
inline void update(int p){
a[p].size = a[ls(p)].size + a[rs(p)].size ;
}
inline void build(int p, int l, int r){
if(l == r){
a[p].val = b[l];
a[p].size = 1;
return ;
}
int mid = l + r >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
update(p);
}
inline int query(int p, int l, int r, int k){
if(l == r){
a[p].size = 0;
return a[p].val ;
}
int mid = l + r >> 1, res = 0;;
if(a[ls(p)].size >= k){
res = query(ls(p), l, mid, k);
}
else {
res = query(rs(p), mid + 1, r, k - a[ls(p)].size );
}
update(p);
return res;
}
int main(){
n = read();
for(int i = 1; i <= n; i++)
b[i] = read();
sort(b + 1, b + n + 1);
build(1, 1, n);
for(int i = 1; i <= n; i++)
c[i] = read();
for(int i = n; i >= 1; i--){
ans[i] = query(1, 1, n, c[i] + 1);
}
for(int i = 1; i <= n; i++){
printf("%d\n",ans[i]);
}
return 0;
}
完结撒花✿✿ヽ(°▽°)ノ✿