【题目描述】
小明最近迷上了一款名为《扫雷》的游戏。
其中有一个关卡的任务如下:
在一个二维平面上放置着 n 个炸雷,第 i 个炸雷 (xi,yi,ri) 表示在坐标 (xi,yi) 处存在一个炸雷,它的爆炸范围是以半径为 ri 的一个圆。
为了顺利通过这片土地,需要玩家进行排雷。
玩家可以发射 m 个排雷火箭,小明已经规划好了每个排雷火箭的发射方向,第 j 个排雷火箭 (xj,yj,rj) 表示这个排雷火箭将会在 (xj,yj) 处爆炸,它的爆炸范围是以半径为 rj 的一个圆,在其爆炸范围内的炸雷会被引爆。
同时,当炸雷被引爆时,在其爆炸范围内的炸雷也会被引爆。
现在小明想知道他这次共引爆了几颗炸雷?
你可以把炸雷和排雷火箭都视为平面上的一个点。
一个点处可以存在多个炸雷和排雷火箭。
当炸雷位于爆炸范围的边界上时也会被引爆。
【输入格式】
输入的第一行包含两个整数 n、m。
接下来的 n 行,每行三个整数 xi,yi,ri,表示一个炸雷的信息。
再接下来的 m 行,每行三个整数 xj,yj,rj,表示一个排雷火箭的信息。
【输出格式】
输出一个整数表示答案。
【数据范围】
对于 40% 的评测用例:0≤x,y≤10的9次方,0≤n,m≤10的3次方,1≤r≤10,
对于 100% 的评测用例:0≤x,y≤10的9次方,0≤n,m≤5×10的4次方,1≤r≤10。
【输入样例】
2 1
2 2 4
4 4 2
0 0 5
【输出样例】
2
【样例解释】
示例图如下,排雷火箭 1 覆盖了炸雷 1,所以炸雷 1 被排除;炸雷 1 又覆盖了炸雷 2,所以炸雷 2 也被排除。
【代码】
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 50010, M = 999997;
int n, m;
struct Circle
{
int x, y, r;
}cir[N];
LL h[M];
int id[M];
bool st[M];
LL get_key(int x, int y)
{
return x * 1000000001ll + y;
}
int find(int x, int y)
{
LL key = get_key(x, y);
int t = (key % M + M) % M;
while (h[t] != -1 && h[t] != key)
if ( ++ t == M)
t = 0;
return t;
}
int sqr(int x)
{
return x * x;
}
void dfs(int x, int y, int r)
{
st[find(x, y)] = true;
for (int i = x - r; i <= x + r; i ++ )
for (int j = y - r; j <= y + r; j ++ )
if (sqr(i - x) + sqr(j - y) <= sqr(r))
{
int t = find(i, j);
if (id[t] && !st[t])
dfs(i, j, cir[id[t]].r);
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i ++ )
{
int x, y, r;
scanf("%d%d%d", &x, &y, &r);
cir[i] = {x, y, r};
int t = find(x, y);
if (h[t] == -1) h[t] = get_key(x, y);
if (!id[t] || cir[id[t]].r < r)
id[t] = i;
}
while (m -- )
{
int x, y, r;
scanf("%d%d%d", &x, &y, &r);
for (int i = x - r; i <= x + r; i ++ )
for (int j = y - r; j <= y + r; j ++ )
if (sqr(i - x) + sqr(j - y) <= sqr(r))
{
int t = find(i, j);
if (id[t] && !st[t])
dfs(i, j, cir[id[t]].r);
}
}
int res = 0;
for (int i = 1; i <= n; i ++ )
if (st[find(cir[i].x, cir[i].y)])
res ++ ;
printf("%d\n", res);
return 0;
}