题目
小明最近迷上了一款名为《扫雷》的游戏。
其中有一个关卡的任务如下:
在一个二维平面上放置着 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,表示一个排雷火箭的信息。
输出
输出一个整数表示答案。
输入样例:
2 1
2 2 4
4 4 2
0 0 5
输出样例:
2
代码
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 5e4+10,M = 999997;
LL h[M];
int n,m;
struct Cir{
int x,y,r;
}cir[N];
bool st[M];
int id[M];
LL getKey(int x,int y){
return x*1000000001ll +y;
}
int sqr(int x){
return x*x;
}
int find(int x,int y){
LL key = getKey(x,y);
int t = (key % M + M) % M;
while(h[t]!=-1 && h[t]!=key)
if(++t == M) t=0;
return t;
}
void dfs(int x,int y,int r){
int t = find(x,y);
st[t] = 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) {
LL key = getKey(x,y);
h[t] = key;
}
if(!id[t] || r>cir[id[t]].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++){
int t = find(cir[i].x,cir[i].y);
if(st[t]) res++;
}
printf("%d",res);
}