Codeforces Round #567 (Div. 2) D. Irrigation(权值线段树+思维)

题目链接
在这里插入图片描述
在这里插入图片描述
题意:有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]);
}
发布了171 篇原创文章 · 获赞 0 · 访问量 5805

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104590698