題意:給一個長爲n的數組,q次詢問(n,q<=5e5),每次給一個k(k<=1e18),求第k次填數是填第幾個數(每次填數選擇最小的數進行+1操作,如果有多個優先加下標最小的那個)
題解:離線,又由於每次改變都是成塊地改變,所以可以成塊改變就成塊改變,不能成塊改變就直接求第k小,可以用權值線段樹求第k小
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;
const int maxn=5e5+5;
const double eps=1e-3;
const ll inf=1e18;
struct pot{
int id;
ll cnt;
}p[maxn],que[maxn];
ll a[maxn],b[maxn];
int c[maxn],ans[maxn];
bool cmp1(struct pot aa,struct pot bb){
if(aa.cnt!=bb.cnt)return aa.cnt<bb.cnt;
return aa.id<bb.id;
}
bool cmp2(struct pot aa,struct pot bb){
if(aa.cnt!=bb.cnt)return aa.cnt<bb.cnt;
return aa.id<bb.id;
}
struct node{
int l;
int r;
int val;
}no[maxn<<2];
void build(int rt,int l,int r){
no[rt].l=l;
no[rt].r=r;
no[rt].val=0;
if(l==r)return;
int mid=(l+r)>>1;
build((rt<<1),l,mid);
build((rt<<1)|1,mid+1,r);
}
void pushup(int rt){
no[rt].val=no[rt<<1].val+no[(rt<<1)|1].val;
}
void update(int rt,int l,int r,int pos){
if(l==r){
no[rt].val=1;
return;
}
int mid=(l+r)>>1;
if(mid>=pos)update((rt<<1),l,mid,pos);
else update((rt<<1)|1,mid+1,r,pos);
pushup(rt);
}
int query(int rt,int l,int r,int pos){
if(l==r)return l;
int mid=(l+r)>>1;
if(no[rt<<1].val>=pos)return query(rt<<1,l,mid,pos);
else return query((rt<<1)|1,mid+1,r,pos-no[rt<<1].val);
}
int main(){
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++){
p[i].id=i;
p[i].cnt=0;
}
for(int i=1;i<=n;i++){
int w;
scanf("%d",&w);
p[w].cnt++;
}
for(int i=1;i<=q;i++){
scanf("%lld",&que[i].cnt);
que[i].cnt-=n;
que[i].id=i;
}
sort(p+1,p+1+m,cmp1);
sort(que+1,que+1+q,cmp2);
build(1,1,m);
int st=0;
ll sum=0;
ll w=0;
for(int i=1;i<=q;i++){
ll k=que[i].cnt-w;
while(st<m&&p[st+1].cnt*st-sum<k){
k-=(p[st+1].cnt*st-sum);
w+=(p[st+1].cnt*st-sum);
sum=p[st+1].cnt*(st+1);
st++;
update(1,1,m,p[st].id);
}
k%=(st);
if(!k)k=st;
int w=query(1,1,m,k);
ans[que[i].id]=w;
}
for(int i=1;i<=q;i++){
printf("%d\n",ans[i]);
}
return 0;
}