题解:P11118 [ROI 2024] 无人机比赛 (Day 2)

洛谷

首先可以发现实际上可以把距离进行压缩,因为我们一旦有一架经过了一段距离,那么在这之后比它小的距离一定也会直接走,所以距离种类最多也不超过 \(547\) 个。

因为从 \(1\) 一直加到 \(547\) 的和使最大的不超过 \(150000\) 的。

然后考虑如何计算,由于要计算 \(n\) 个结果,所以我们考虑将一个个无人机插入进去的结果。

首先是插入进去的无人机刷新别的无人机的次数,其次是自己被别的无人机刷新的次数。

先考虑插入进去的无人机刷新别的无人机的次数如何计算。

我们只需要知道这个无人机在走这个距离的时候还有哪些无人机没有走到终点即可。

对于每一个无人机的每一个距离进行查询,为了平衡时间复杂度,我们每次查询需要 \(O(1)\) 的时间复杂度,可以使用分块。

再考虑插入进去的无人机被别的无人机刷新的次数如何计算。

相反,我们需要考虑每一个别的无人机在某一个时刻是否会存在这个新的无人机还在的情况,同理使用分块平衡时间复杂度。

但是剩下的问题是分块如何设计,如果直接使用时间记录明显不行,但是我们只需要知道有几个还没有走到最后就行了。

所以我们可以将其按照到达最终位置顺序分开,然后预处理出每一个无人机走到某个距离有哪些已经走到终点了。这部分可以用双指针来做。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,t[150005],s[150005],id[150005],tt[555],cnt,pos[150005][555],B,rk[150005],idd[150005],L[150005],R[150005];
long long ans[150005],t1[150005],t2[150005],t3[150005],t4[150005];
bool cmp(int x,int y){
	if(t[x]==t[y])return x<y;
	return t[x]<t[y];
}
void update1(int p,int v){
	t1[p]+=v;t2[idd[p]]+=v;
}
long long query1(int p){
	long long res=0;
	for(int i=p;i<=R[idd[p]];i++)res+=t1[i];
	for(int i=idd[p]+1;i<=idd[n];i++)res+=t2[i];
	return res;
}
long long query2(int p){
	return t3[p]+t4[idd[p]-1];
}
void update2(int p,int v){
	for(int i=p;i<=R[idd[p]];i++)t3[i]+=v;
	for(int i=idd[p];i<=idd[n];i++)t4[i]+=v;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++)cin>>t[i];
	for(int i=1;i<=m;i++)cin>>s[i];
	for(int i=1;i<=n;i++)id[i]=i;
	sort(id+1,id+n+1,cmp);
	for(int i=1;i<=n;i++)rk[id[i]]=i;
	for(int i=m;i>=1;i--)s[i]-=s[i-1];
	for(int i=1,w=1;i<=m;i=w+1,w=i){
		s[++cnt]=s[i],tt[cnt]=1;
		while(w<m&&s[w+1]<=s[cnt])w++,tt[cnt]++;
	}
	for(int j=1;j<=cnt;j++){
		for(int i=1,w=0;i<=n;i++){
			while(w<n&&(1ll*t[id[w+1]]*s[j]<1ll*t[id[i]]*s[cnt]||1ll*t[id[w+1]]*s[j]==1ll*t[id[i]]*s[cnt]&&id[w+1]<=id[i]))w++;
			pos[id[i]][j]=w;
		}
	}
	B=sqrt(n)+1;
	for(int i=1;i<=n;i++){
		idd[i]=(i-1)/B+1;
		if(!L[idd[i]])L[idd[i]]=i;
		R[idd[i]]=i;
	}
	for(int i=1;i<=n;i++){
		ans[i]=ans[i-1]+query1(rk[i]);
		for(int j=1;j<=cnt;j++)update1(pos[i][j],tt[j]);
		for(int j=1;j<=cnt;j++)ans[i]+=query2(pos[i][j])*tt[j];
		update2(rk[i],1);
		cout<<ans[i]<<endl;
	}
	return 0;
}
posted @ 2026-07-13 20:46  huhangqi  阅读(7)  评论(0)    收藏  举报