Luogu P10590 磁力块

P10590 磁力块

有一个很显然的 BFS,对于每一个吸到的新磁力块,遍历序列,把所有它能吸到的磁力块加入一个队列进行扩展。这样时间复杂度是 O(n2),不能通过。

考虑影响是否能吸到的两个因素,一个是利用 x,y 计算出的距离,另一个是质量 m。对于这种问题,经典的做法是排序维护第一个变量,数据结构维护第二个变量。

由于本题需要取出可以吸到的磁力块入队,故 log 数据结构在本题中不好用。我们考虑分块。把所有磁力块按照距离升序排序,每 n 个元素分成一块。块内按照 m 升序排序,并记录距离的最大值。

当我们扩展一个磁力块时,从小到大遍历序列中的每一块。

对于一个最大距离小于等于吸引半径的块,所有磁力块均处于吸引半径之内。可以对于每一块记录一个 la,表示块中已经前 la1 个磁力块已经被吸引。我们只需要利用 la,遍历到第 x 个元素,使这个元素的 m 大于当前吸力即可。由于 m 升序排序,所以这一块中所有可以被吸走的磁力块要么在之前被吸走,要么在这一次被吸走,满足条件。之后,令 la=x

对于第一个最大距离大于吸引半径的块,根据遍历顺序以及距离升序排序,之后的块中所有元素距离必然大于吸引半径,可以处理完这一块之后退出循环。这一块之中有的磁力块可以被吸走,有的磁力块不可以被吸走。我们暴力求出每一个能够吸走的磁力块,标记已经被吸走,之后排序重构。均衡复杂度之后为 O(nnlogn)可以通过

事实上,可以继续优化。在处理第一个最大距离大于吸引半径的块时,我们不进行排序重构。改为在处理最大距离小于等于吸引半径的块时,如果遇到一个被吸走的磁力块,直接跳过到下一个。由于 m 升序排序,依旧满足要求。时间复杂度 O(nn)

#include <bits/stdc++.h>
using namespace std;
struct val
{
	long long m,p,r;
	double d;
}a[300000];
long long xq,yq,x,y,p,r,n,k,qp[300000],qr[300000],h=1,t=0,id[300000],la[300000],lc[300000],rc[300000],ans=-1;
double mx[300000];
bool cmp1(struct val a,struct val b)
{
	return a.d<b.d;
}

bool cmp2(struct val a,struct val b)
{
	return a.m<b.m;
}

double dist(long long x1,long long y1,long long x2,long long y2)
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

void expand(long long p,long long r)
{
	for(int i=1;i<=(n+k-1)/k;i++)
	    if(mx[i]<=r)
	       while(a[la[i]].m<=p&&la[i]<=rc[i])
               {
               if(a[la[i]].m!=-1e10)qp[++t]=a[la[i]].p,qr[t]=a[la[i]].r,a[la[i]].m=-1e10;
               la[i]++;
               }
	    else
	       {
	       	la[i]=lc[i];
	       	for(int j=lc[i];j<=rc[i];j++)
	       	    if(a[j].m!=-1e10&&a[j].m<=p&&a[j].d<=r)qp[++t]=a[j].p,qr[t]=a[j].r,a[j].m=-1e10;
	       	break;
		   }
}

int main()
{
	scanf("%lld%lld%lld%lld%lld",&xq,&yq,&p,&r,&n);
	qp[++t]=p,qr[t]=r,k=sqrt(n);
	for(int i=1;i<=n;i++)
	    {
	    	scanf("%lld%lld%lld%lld%lld",&x,&y,&a[i].m,&a[i].p,&a[i].r);
	    	a[i].d=dist(xq,yq,x,y);
		}
	sort(a+1,a+n+1,cmp1);
	for(int i=1;i<=(n+k-1)/k;i++)lc[i]=1e10;
	for(long long i=1;i<=n;i++)id[i]=(i-1)/k+1,lc[id[i]]=min(lc[id[i]],i),rc[id[i]]=max(rc[id[i]],i),mx[id[i]]=max(mx[id[i]],a[i].d);
	for(int i=1;i<=(n+k-1)/k;i++)la[i]=lc[i],sort(a+lc[i],a+rc[i]+1,cmp2);
	while(h<=t)ans++,expand(qp[h],qr[h]),h++;
	printf("%lld\n",ans);
	return 0;
}
posted @   w9095  阅读(0)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示