题目链接
思路爆炸!!!这道题简直了,我写这片文章给自己理清思路,也给读者一个清晰的写法。
思路:
很明显的离散化,点少、值大,所以用了离散化,怎么离散化呢??我的想法就是对于x我们进行离散化,然后只需要去找符合条件的y即可确定爆炸与否(题目还是人性化的给的是曼哈顿距离,不然真的是得有KD-Tree还真不会),我们在输入的时候把x存入x_hash[]的数组中去,存完后对x_hash[]进行个升序排序,然后就可以用unique()函数进行去重操作,它的去重并非真正意义上的删除,只是把相同的元素排到最后面去而已,然后利用数组的特性去得道不重复元素的个数,然后题目讲到一点,可能有多个雷在同一点上,于是我一开始想写的set()改成了multiset()——不去重的set(),之后,清空其1~hash_cnt(哈希表的长度,不同元素的个数)的元素,留空出来好插入元素,之后,对全体元素进行逐一处理,现在的x的正确ID变成了它在哈希表上的位置了。
以上是离散化的操作,然后我们来探讨一下——如何去知道到底这次的爆炸会炸开多少地雷?已知点->未知点!BFS试一下,还真的可行,我们知道起点s,就是自爆点,其中要是自爆点已经爆过了,那么直接返回0,然后就是正规操作了,对于起点的x,我们可以用其知道x在哈希表上的可行范围(用二分的lower_bound()或者upper_bound()来做),x的哈希表上的范围在于目前点的坐标的圆最大可达距离点,然后我们再由x的遍历去限制y(也可以说是如此去找到对应的y),也是需要二分来查找的,这时候就意味着需要重载结构体中的函数了,将x看作数组的下标,以此查找区间内满足条件的(x,y)点,对于y,我们直接查找它在结构体的哪个位置,同样的查找的区间为满足目前点的圆的最大可达距离,但是因为此时的半径不再是其原本半径了,而是要剪去对应已经走出的x的距离才是y的半径,然后直接用查询到的点所“->”的ID是否爆炸,最后退出循环的时候最好删除这些已经遍历过的点,这样可以节约时间。
完整代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
typedef long long ll;
const int maxN=100005;
int N, M;
int Abs(int x) { return x>0?x:(-x); }
bool cmp(int e1, int e2) { return e1<e2; }
bool boom[maxN]; //是否已经爆炸的点
struct point //记录正统(原)状态
{
int x, y, rd;
point(int a=0, int b=0, int c=0):x(a), y(b), rd(c) {}
}a[maxN];
int x_hash[maxN], hash_cnt; //对于x进行哈希(离散化),得出一共有多少个哈希点
struct node //是哈希过后,用其记录对应的y坐标,以及该数的id,毕竟关系到爆炸点问题
{
int y, id; //y坐标,与x的对应点
node(int a=0, int b=0):y(a), id(b) {}
friend bool operator < (node e1, node e2)
{
return e1.y<e2.y;
}
};
multiset<node> mst[maxN];
int bfs(int s)
{
if(boom[s]) return 0;
int ans=0; boom[s]=true;
queue<int> Q;
Q.push(s);
multiset<node>::iterator yl, yr, it;
while(!Q.empty())
{
ans++;
int u=Q.front(); Q.pop();
int xl=(int)( lower_bound(x_hash+1, x_hash+1+hash_cnt, a[u].x-a[u].rd) - x_hash ); //下限
int xr=(int)( upper_bound(x_hash+1, x_hash+1+hash_cnt, a[u].x+a[u].rd) - x_hash - 1); //上限
for(int i=xl; i<=xr; i++)
{
int yy=a[u].rd - Abs(a[u].x - x_hash[i]);
yl=mst[i].lower_bound(node(a[u].y - yy, 1));
yr=mst[i].upper_bound(node(a[u].y + yy, 1));
for(it=yl; it!=yr; it++)
{
if(!boom[it->id])
{
boom[it->id]=true;
Q.push(it->id);
}
}
mst[i].erase(yl, yr);
}
}
return ans;
}
int main()
{
int Cas=0;
while(scanf("%d", &N) && N)
{
for(int i=1; i<=N; i++)
{
scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].rd);
x_hash[i]=a[i].x;
}
sort(x_hash+1, x_hash+1+N, cmp);
hash_cnt=(int)( unique(x_hash+1, x_hash+1+N) - x_hash - 1); //unique并非把相同的去掉了,而是把他们放到了最后面
for(int i=1; i<=hash_cnt; i++) { mst[i].clear(); }
for(int i=1; i<=N; i++)
{
int id=(int)( lower_bound(x_hash+1, x_hash+1+hash_cnt, a[i].x) - x_hash );
mst[id].insert(node(a[i].y, i)); //以x所在的序位来推y
}
scanf("%d", &M); //M次查询操作
printf("Case #%d:\n", ++Cas);
memset(boom, false, sizeof(boom));
for(int i=1; i<=M; i++)
{
int e1; scanf("%d", &e1);
printf("%d\n", bfs(e1));
}
}
return 0;
}
第二次写:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi acos(-1.0)
#define e exp(1.0)
using namespace std;
typedef long long ll;
const int maxN=100005;
int N, M;
bool cmp(int e1, int e2) { return e1<e2; }
int Abs(int x) { return x>0?x:(-x); }
struct mine
{
int x, y, r;
mine(int a=0, int b=0, int c=0):x(a), y(b), r(c) {}
}point[maxN];
int x_hash[maxN], hash_cnt; bool boom[maxN];
struct node
{
int y, id;
node(int a=0, int b=0):y(a),id(b) {}
friend bool operator < (node e1, node e2)
{
return e1.y<e2.y;
}
};
multiset<node> mst[maxN];
int bfs(int s)
{
if(boom[s]) return 0;
int ans=0;
queue<int> Q;
Q.push(s); boom[s]=true;
while(!Q.empty())
{
int u=Q.front(); Q.pop(); ans++;
int xl, xr; multiset<node>::iterator yl, yr, it;
xl=(int)( lower_bound(x_hash+1, x_hash+1+hash_cnt, point[u].x - point[u].r) - x_hash);
xr=(int)( upper_bound(x_hash+1, x_hash+1+hash_cnt, point[u].x + point[u].r) - x_hash - 1);
for(int i=xl; i<=xr; i++)
{
int yy=point[u].r - Abs(point[u].x - x_hash[i]);
yl=mst[i].lower_bound(node(point[u].y-yy, 1));
yr=mst[i].upper_bound(node(point[u].y+yy, 1));
for(it=yl; it!=yr; it++)
{
if(!boom[it->id])
{
Q.push(it->id);
boom[it->id]=true;
}
}
mst[i].erase(yl, yr);
}
}
return ans;
}
int main()
{
int Cas=0;
while(scanf("%d", &N) && N)
{
for(int i=1; i<=N; i++)
{
scanf("%d%d%d", &point[i].x, &point[i].y, &point[i].r);
x_hash[i]=point[i].x;
}
sort(x_hash+1, x_hash+1+N, cmp);
hash_cnt=(int)( unique(x_hash+1, x_hash+1+N) - x_hash - 1);
for(int i=1; i<=hash_cnt; i++) mst[i].clear();
for(int i=1; i<=N; i++)
{
int id=(int)( lower_bound(x_hash+1, x_hash+1+hash_cnt, point[i].x) - x_hash );
mst[id].insert(node(point[i].y, i));
}
scanf("%d", &M);
printf("Case #%d:\n", ++Cas); memset(boom, false, sizeof(boom));
for(int i=1; i<=M; i++)
{
int id; scanf("%d", &id);
printf("%d\n", bfs(id));
}
}
return 0;
}