zoukankan      html  css  js  c++  java
  • CH#46A 磁力块(BFS+分块)

    在一片广袤无垠的原野上,散落着N块磁石。

    每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径。

    若磁石A与磁石B的距离不大于磁石A的吸引半径,并且磁石B的质量不大于磁石A的磁力,那么A可以吸引B。

    小取酒带着一块自己的磁石L来到了这片原野的(x0,y0)(x0,y0)处,我们可以视磁石L的坐标为(x0,y0)(x0,y0)。

    小取酒手持磁石L并保持原地不动,所有可以被L吸引的磁石将会被吸引过来。

    在每个时刻,他可以选择更换任意一块自己已经获得的磁石(当然也可以是自己最初携带的L磁石)在(x0,y0)(x0,y0)处吸引更多的磁石。

    小取酒想知道,他最多能获得多少块磁石呢?

    输入格式

    第一行五个整数x0,y0,pL,rL,Nx0,y0,pL,rL,N,表示小取酒所在的位置,磁石L磁力、吸引半径和原野上散落磁石的个数。

    接下来N行每行五个整数x,y,m,p,r,描述一块磁石的性质。

    输出格式

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

    数据范围

    1N2500001≤N≤250000,
    109x,y109−109≤x,y≤109,
    1m,p,r1091≤m,p,r≤109

    输入样例:

    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

    蓝书解释的很清楚了,及时维护块的左端点很巧妙。注释里有详解。
    #include <bits/stdc++.h>
    #define SIZE 250005
    using namespace std;
    int x0, y00, pl, rl, N, ans = 0;
    int L[SIZE], R[SIZE], pos[SIZE], t;
    bool vis[SIZE] = {0};
    struct Stone{
        int x, y, m, p, r;
        double dis;//距离 
    } s[SIZE];
    double calc(Stone a, Stone b){
        return sqrt(1ll * (a.x - b.x) * (a.x - b.x) + 1ll * (a.y - b. y) * (a.y - b.y));
    }
    bool cmp1(Stone a, Stone b){
        return a.m < b.m;
    }
    bool cmp2(Stone a, Stone b){
        return a.dis < b.dis;
    }
    queue<Stone> q;
    void BFS(){
        int m = 0;
        q.push(Stone{x0, y00, m, pl, rl});
        while(q.size()){
            Stone temp = q.front();
            q.pop();
            for(int i = 1; i <= t; i++){//遍历块 
                int cnt = 0, j;//cnt为当前块内质量大于当前手持磁石引力的数目 
                for(j = L[i]; j <= R[i]; j++){//遍历块内 
                    if(s[j].m > temp.p) cnt++;//通过cnt变量来判断当前块内磁石质量是否全部小于手持磁石引力,以此来确定是否是“边角块 ” 
                    else{
                        if(s[j].dis <= 1ll * temp.r){//首先判断距离 
                            if(!vis[j]){//其次判断是否访问过。因为对于某次循环的“边角块”而言,其含有的磁石可能已经入队,但区间端点并未改变,因此要额外判定 
                                ans++;
                                  vis[j] = 1;
                                  q.push(s[j]);
                             }
                        }
                        else break;//因为块内已经按距离排序了,大于的话直接结束当前块的循环 
                    }
                }
                if(!cnt) L[i] = j;//质量全部小于的时候(说明当前块非边角块)才更新端点 
                else break;//当前块内有质量大于手持磁石引力的磁石了,说明为边角块,直接结束循环 
            }
        }
    }
    int main(){
        cin >> x0 >> y00 >> pl >> rl >> N;
        for(int i = 1; i <= N; i++) {
            scanf("%d%d%d%d%d", &s[i].x, &s[i].y, &s[i].m, &s[i].p, &s[i].r);
            s[i].dis = calc(s[i], Stone{x0, y00, 0, 0, 0});
        }
        sort(s + 1, s + N + 1, cmp1);//整体按照质量排序 
        //常规分块预处理 
        t = sqrt(N);
        for(int i = 1; i <= t; i++){
            L[i] = (i - 1) * sqrt(N) + 1;
            R[i] = i * sqrt(N);
        }
        if(R[t] < N) t++, L[t] = R[t - 1] + 1, R[t] = N; 
        for(int i = 1; i <= t; i++){
            for(int j = L[i]; j <= R[i]; j++){
                pos[j] = i;
            }
        }
        for(int i = 1; i <= t; i++){
            sort(s + L[i], s + R[i] + 1, cmp2);//块内按照距离排序 
        }
        BFS();
        cout << ans;
    }
     
  • 相关阅读:
    Android 2.2 r1 API 中文文档系列(11) —— RadioButton
    Android API 中文 (15) —— GridView
    Android 中文 API (16) —— AnalogClock
    Android2.2 API 中文文档系列(7) —— ImageButton
    Android2.2 API 中文文档系列(6) —— ImageView
    Android 2.2 r1 API 中文文档系列(12) —— Button
    Android2.2 API 中文文档系列(8) —— QuickContactBadge
    [Android1.5]TextView跑马灯效果
    [Android1.5]ActivityManager: [1] Killed am start n
    Android API 中文(14) —— ViewStub
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/13311433.html
Copyright © 2011-2022 走看看