题意
有
m
m
m个城市,已经举办过
n
n
n次比赛,接下来比赛举办地的规则为:选出举办过比赛次数最少且编号最小的城市举办比赛。有
q
q
q次询问,问第
k
i
k_i
ki届比赛在那个城市举行。
1
≤
n
,
m
,
q
≤
500000
,
n
+
1
≤
k
i
≤
1
0
18
1≤n,m,q≤500000, n+1\le k_i \le 10^{18}
1≤n,m,q≤500000,n+1≤ki≤1018
解法
询问离线,并升序排序。城市按照举办次数升序排序,计算相邻两个对总举办数的贡献,在总数以内的答案可以计算出来城市编号的排名,用权值线段树等数据结构维护即可(代码采用权值树状数组)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1<<19;
int a[N],r[N];
bool cmp(int x,int y){
if(a[x]==a[y])return x<y;
return a[x]<a[y];
}
int t[N];
int find(int x){
int p=N>>1,ans=0;
for(int lb=p;lb;){
lb>>=1;
if(t[p]>=x)p-=lb;
else {ans=p;x-=t[p];p+=lb;}
}
return ans+1;
}
void add(int p){
for(;p<N;p+=(p&-p))t[p]++;
}
struct que{
ll k;
int i;
bool operator<(que b)const{
return i<b.i;
}
}qs[N];
bool cmpq(que x,que y){
return x.k<y.k;
}
int main(){
ios::sync_with_stdio(0);
int n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=m;i++)r[i]=i;
for(int i=0,x;i<n;i++){
cin>>x;a[x]++;
}
sort(r+1,r+m+1,cmp);
for(int i=0;i<q;i++){
cin>>qs[i].k;
qs[i].i=i;
}
sort(qs,qs+q,cmpq);
int l=0;
ll s=n;
for(int i=1;i<=m;i++){
ll sx=s;
if(i==m)s=2e18;
else s+=ll(a[r[i+1]]-a[r[i]])*i;
add(r[i]);
while(l<q && qs[l].k<=s){
qs[l].k=find((qs[l].k-sx-1)%i+1);
l++;
}
}
sort(qs,qs+q);
for(int i=0;i<q;i++)
cout<<qs[i].k<<'\n';
return 0;
}