题目链接
题意:有m个城市要举办奥运会,现在给出前n年举办过奥运会的城市编号,第n年后举办奥运会的城市要符合以下规则:1、优先选m个城市里举办奥运会次数最少的城市;2、如果这样的城市有多个,优先选编号较小的。
现给出q个询问,每个询问表示第x年的举办奥运会的城市是哪个?
思路:我们可以发现举办奥运会的城市是存在周期性规律的,按举办次数从小到达排序,到第i个城市举办的年份是可以一步步递推出来的,假设最后判断出来是在第1到i个城市中的第k小个,由于是按次数排序,所有城市的编号不一定有序,所有可以用权值线段树求第k小。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+1;
int n,m,t,Q;
ll ans[maxn];
struct cxk{
int l,r;
ll val;
}tree[maxn<<2];
struct node{
ll cnt;
int id;
}p[maxn],q[maxn];
bool cmp(const node &a,const node &b)
{
return a.cnt==b.cnt?a.id<b.id:a.cnt<b.cnt;
}
void build(int l,int r,int x)
{
tree[x].l=l;tree[x].r=r;
if(l==r){
tree[x].val=0;return ;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
tree[x].val=tree[x<<1].val+tree[x<<1|1].val;
}
void update(int pos,int x)
{
if(tree[x].l==tree[x].r) {tree[x].val=1;return ;}
int mid=(tree[x].l+tree[x].r)>>1;
if(pos<=mid) update(pos,x<<1);
else update(pos,x<<1|1);
tree[x].val=tree[x<<1].val+tree[x<<1|1].val;
}
int query(int pos,int x)
{
if(tree[x].l==tree[x].r) return tree[x].l;
int mid=(tree[x].l+tree[x].r)>>1;
if(tree[x<<1].val>=pos) return query(pos,x<<1);
else return query(pos-tree[x<<1].val,x<<1|1);
}
int main()
{
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=m;++i) p[i].cnt=0,p[i].id=i;
for(int i=1;i<=n;++i)
scanf("%d",&t),p[t].cnt++;
for(int i=1;i<=Q;++i)
scanf("%lld",&q[i].cnt),q[i].cnt-=n,q[i].id=i;
sort(q+1,q+1+Q,cmp);
sort(p+1,p+1+m,cmp);
build(1,m,1);
ll sum=0,last=0,now=0;
for(int i=1;i<=Q;++i)
{
ll k=q[i].cnt-last;
while(now<m&&p[now+1].cnt*now-sum<k)
{
k-=p[now+1].cnt*now-sum;
last+=p[now+1].cnt*now-sum;
sum=p[now+1].cnt*(now+1);
now++;
update(p[now].id,1);
}
k%=(now);
if(k==0) k=now;
ans[q[i].id]=query(k,1);
}
for(int i=1;i<=Q;++i)
printf("%lld\n",ans[i]);
}