问题 E: 【蓝桥杯2022初赛】扫雷

(建图搜索 + 二分查询) O(nlog(n)O(nlog(n)
1, 对所有炸弹按x坐标排序
2,建图 若A可以引爆B则建一条A指向B的边
3,对每一个排雷火箭进行二分查询,找到可能引爆的炸弹的下标的范围
4,找到3中的炸弹后按图搜索即可

#include <bits/stdc++.h>
using namespace std;
#define de(x) cout << x << " ";
#define sf(x) scanf("%d", &x);
#define Pu puts("");
#define ll long long
const int N = 5e4 + 10, M = 1e7 + 10;
int n, m;
int hed[N], nxt[M], var[M], tot;
bool st[N];
int ans;
// 相当于二维数组,作用是记录某点处是否有炸雷
map<pair<int, int>, int> mp;
struct E {
    int x, y, r, cnt;
    bool operator<(const E& t) const {  // 自定义排序,按照从小到大的顺序
        if (x != t.x)
            return x < t.x;
        return y < t.y;
    }
} e[N];
int cn;  // 去重后的炸雷数量
void add(int x, int y) {
    var[++tot] = y;
    nxt[tot] = hed[x];
    hed[x] = tot;
}
int dfs2(int x) {
    st[x] = true;
    int res = e[x].cnt;
    for (int i = hed[x]; i; i = nxt[i]) {
        if (st[var[i]] == true)
            continue;
        res += dfs2(var[i]);
    }
    return res;
}
void dfs(int x, int y, int r) {
    E e1 = {x - r - 1, y, r};
    E e2 = {x + r + 1, y, r};
    // 这里运用了二分,我的理解是,找结构体中的第一个参数,也就是x的值
    // 第一个大于等于改x值的结构体下标
    int l = lower_bound(e + 1, e + cn + 1, e1) - e;
    int r1 = lower_bound(e + 1, e + cn + 1, e2) - e;
    l = min(cn, l);
    r1 = min(cn, r1);
    for (int i = l; i <= r1; i++) {
        int t1 = abs(e[i].x - x) * abs(e[i].x - x) +
                 abs(e[i].y - y) * abs(e[i].y - y) - r * r;
        if (t1 <= 0 && st[i] == false) {
            ans += dfs2(i);
        }
    }
}
int main() {
    cin >> n >> m;
    int x, y, r;
    for (int i = 1; i <= n; i++) {
        sf(x) sf(y) sf(r);
        int t1 = mp[{x, y}];  // 判断这点处是否有炸雷
        if (t1 == 0) {
            e[++cn].x = x;
            e[cn].y = y;
            e[cn].r = r;
            e[cn].cnt++;
            mp[{x, y}] = cn;
        } else {
            e[t1].cnt++;
            e[t1].r = max(r, e[t1].r);
        }
    }
    sort(e + 1, e + cn + 1);  // 开始建边
    for (int i = 1; i <= cn; i++) {
        int dis = e[i].r * e[i].r;
        for (int j = i - 1; j >= 1; j--) {
            int t1 = abs(e[i].x - e[j].x) * abs(e[i].x - e[j].x);
            if (t1 > dis)
                break;
            if (abs(e[i].x - e[j].x) * abs(e[i].x - e[j].x) +
                    abs(e[i].y - e[j].y) * abs(e[i].y - e[j].y) <=
                dis) {
                add(i, j);
            }
        }
        for (int j = i + 1; j <= cn; j++) {
            int t1 = abs(e[i].x - e[j].x) * abs(e[i].x - e[j].x);
            if (t1 > dis)
                break;
            if (abs(e[j].x - e[i].x) * abs(e[j].x - e[i].x) +
                    abs(e[j].y - e[i].y) * abs(e[j].y - e[i].y) <=
                dis) {
                add(i, j);
            }
        }
    }
    for (int i = 1; i <= m; i++) {
        sf(x) sf(y) sf(r);
        dfs(x, y, r);
    }
    de(ans);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值