• AcWing 250 磁力快(分块)


    题目传送门

    在一片广袤无垠的原野上,散落着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)。

    数据范围

    (1≤N≤250000, −10^9≤x,y≤10^9, 1≤m,p,r≤10^9)

    输入样例:

    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
    

    分析

    将磁石按照质量排序,分成t块,然后对于一个磁石一定有一个k,使得前k-1块所有的磁石的质量都小于它的磁力,k+1块之后的磁石质量都比它磁力大,而对块内按照距离排序之后,只需要挨个扫就可以了,扫过的标记、加入队列,调整区间。但对于第k块,因为不是所有的质量都小于当前磁块的磁力,所以要全部扫一遍,直到距离大于磁力半径,该块不能被调整区间

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 250010;
    struct node{
        int x,y,m,p,r;
        double dis;
    }a[N];
    int x0,y,n;
    int L[N],R[N],v[N];
    double S(int x){return 1.0*x * x;}
    bool cmp(node a,node b){
        return a.m < b.m;
    }
    bool cmp2(node a,node b){
        return a.dis < b.dis;
    }
    int main(){
        scanf("%d%d%d%d%d",&x0,&y,&a[0].p,&a[0].r,&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d%d%d%d",&a[i].x,&a[i].y,&a[i].m,&a[i].p,&a[i].r);
            a[i].dis = sqrt(S(a[i].x-x0)+S(a[i].y-y));
        }
        int t = sqrt(n);
        for(int i=1;i<=t;i++){
            L[i] = (i-1) * t + 1;
            R[i] = i * t;
        }
        if(R[t] < n){
            t ++;L[t] = R[t-1] + 1;R[t] =n;
        }
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=t;i++){
            sort(a+L[i],a+R[i]+1,cmp2);
        }
        int res = 0;
        queue<int> q;
        q.push(0);
        while(!q.empty()){
            int u = q.front();q.pop();
            res++;
            int r = a[u].r,p = a[u].p;
            bool flag = true;//标记是否为前k-1块
            for(int i=1;i<=t;i++){
                if(!flag)break;
                int j = L[i];
                for(;j<=R[i];j++){
                    if(v[j])continue;
                    if(p >= a[j].m){
                        if(r >= a[j].dis){
                            v[j] = 1;q.push(j);
                        }else{
                            break;
                        }
                    }else{
                        flag = false;continue;//是第k块
                    }
                }
                if(flag)L[i] = j;//不是第k块就调整左坐标点
            }
        }
        printf("%d
    ",res-1);//减去原始的磁石
        return 0;
    }
    
  • 相关阅读:
    会员管理软件
    正则表达式查找未记录的异常
    网络通信 数据压缩后发送
    SQL 工具系列一
    P5443 [APIO2019]桥梁 [分块+并查集]
    #6499. 「雅礼集训 2018 Day2」颜色 [分块,倍增,bitset]
    CF594D REQ [离线+树状数组,欧拉函数]
    雅礼集训板刷合集
    [HNOI2016]网络 [树链剖分,可删除堆]
    「BZOJ3065」带插入区间K小值 [分块]
  • 原文地址:https://www.cnblogs.com/1625--H/p/11310523.html
Copyright © 2020-2023  润新知