• 磁力块


    题目描述

    在一片广袤无垠的原野上,散落着N块磁石。每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径。若磁石A与磁石B的距离不大于磁石A的吸引半径,并且磁石B的质量不大于磁石A的磁力,那么A可以吸引B。
    小取酒带着一块自己的磁石L来到了这篇原野的(x0,y0)处,我们可以视为磁石L的坐标为(x0,y0)。小取酒手持磁石L并保持原地不动,所有可以被L吸引的磁石将会被吸引过来。在每个时刻,他可以选择更换任意一块自己已经获得的磁石(当然也可以是自己最初携带的L磁石)在(x0,y0)处吸引更多的磁石。小取酒想知道,他最多能获得多少块磁石呢?

    输入

    第一行五个整数x0,y0,pL,rL,N,表示小取酒所在的位置,磁石L磁力、吸引半径和原野上散落磁石的个数。
    接下来N行每行五个整数x,y,m,p,r,描述一块磁石的性质。

    输出

    输出一个整数,表示最多可以获得的散落磁石个数(不包含最初携带的磁石L)

    样例输入

    0 0 5 10 5
    5 4 7 11 5
    -7 1 4 7 8
    0 2 13 5 6
    2 -3 9 3 4
    13 5 1 9 9
    

    样例输出

    3

    提示

    对于30%的数据,1<=N<=1000。
    对于另外30%的数据,p=r。
    对于100%的数据,1<=N<=250000,-10^9<=x,y<=10^9,1<=m,p,r<=10^9。

    BFS,把手里的磁石放进队列中,每次将队首元素能吸引的加进来
    问题就是快速判断哪些磁石能被吸引
    能被吸引的磁石需要满足 m<=p, dis<=r 
    先把所有磁石按照质量排序,然后分块,每块内按照距离重新排序
    那么对当前磁石来说,肯定存在一个k,前1~k段每块磁石质量都比该块磁石的磁力小,k+1段之后每块磁石质量都比它大
    对于1~k段,因为每块内都按照距离排序了,因此能被吸引的一定是位于该段开头部分,我们从前往后扫描,扫到不能吸引为止,然后更新区间左端点
    对于第k段,暴力扫描,把能吸引的加进来即可
    复杂度o(n√n)
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=3e5+10;
    const int block=500;
    int n,m,cnt;
    double x,y,xx,yy;
    int L[block],R[block],M[block];
    bool vis[N];
    struct orz{
        int p,r;};
    queue<orz>q;
    struct stu{
        int p,r,m;
        double dis;}a[N];
    double dist(double x,double y)
    {
        return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
    }
    bool cmp1(stu a,stu b)
    {
        return a.m<b.m;
    }
    bool cmp2(stu a,stu b)
    {
        return a.dis<b.dis;
    }
    int main()
    {
        int p,r,n;
        scanf("%lf%lf%d%d%d",&xx,&yy,&p,&r,&n);
    
        for (int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&x,&y);
            a[i].dis=dist(x,y);
            scanf("%d%d%d",&a[i].m,&a[i].p,&a[i].r);
        }
        sort(a+1,a+1+n,cmp1);
    
        for (int i=1;i<=n;i+=block)
        {
            L[++cnt]=i;R[cnt]=min(cnt*block,n);
            M[cnt]=a[R[cnt]].m;
            sort(a+i,a+R[cnt]+1,cmp2);
        }
    
        int ans=0;
        q.push({p,r});
        while (!q.empty())
        {
            orz now=q.front();
            q.pop();
    
            for (int i=1;i<=cnt;i++)
            {
                if (M[i]>now.p)
                {
                    for (int j=L[i];j<=R[i];j++)
                    if (a[j].m<=now.p && a[j].dis<now.r && !vis[j])
                    {
                        vis[j]=1;
                        ans++;
                        q.push({a[j].p,a[j].r});
                    }
                    break;
                }
    
                while (L[i]<=R[i] && a[L[i]].dis<=now.r)
                {
                    if (!vis[L[i]])
                    {
                        vis[L[i]]=1;
                        ans++;
                        q.push({a[L[i]].p,a[L[i]].r});
                    }
                    L[i]++;
                }
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    mysql中profile的使用
    6、MySQL索引种类
    MySql事务
    MySQL视图(view)
    MySql数据库命令基本操作
    2、MySQL常见数据库引擎及比较?
    1、列举常见的关系型数据库和非关系型都有那些?
    Python中的顺序表
    双端队列
    手持移动端特殊链接:打电话,发短信,发邮件
  • 原文地址:https://www.cnblogs.com/tetew/p/9818385.html
Copyright © 2020-2023  润新知