参考了这篇博客的代码:ZOJ 3521 Fairy Wars【并查集,扫描线,set维护】 - From A Start,As An Acmer - C++博客
这道题融合了两种算法,既有图论也有计算几何,但总体上不算难。
题目大意为:在平面上有一些子弹,如果子弹被冰冻那么以炸弹为中心的,边长为L的正方形以内的子弹都会被冰冻,从而引发连锁反应。现在放法术让以x0和y0为圆心,r为半径的圆内的所以子弹冰冻,求最后会有多少颗子弹被冰冻。
并查集找出所有联通块:先对点按x排序,维护两个指针,把点一次加入set中【按y排序,为了避开重点,second选值为点的序号】,一头一尾,首先都指向数组头部。然后移动尾部,必要时移动头部使得两指针间的点的x间距恰不大于L/2,然后每填加进一个点都判断和前一个点和后一个点的y间距是否大于L/2,如果符合条件,则加入同一个集合。
最后暴力搜一遍和点(x0, y0)距离小于r的点,找出所有相交的集合即可。
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <set>
#define LL long long
using namespace std;
const int maxn = 50005;
typedef struct Point
{
LL x, y;
Point() {}
Point(LL _x, LL _y):
x(_x), y(_y) {}
Point operator -(const Point &argu) const
{
return Point(x - argu.x, y - argu.y);
}
bool operator <(const Point &argu) const
{
if(x == argu.x)
return y < argu.y;
return x < argu.x;
}
LL len2()
{
return x * x + y * y;
}
}pp;
pp p[maxn], c;
typedef set< pair<LL, int> > ss;
ss s;
ss::iterator it;
LL ABS(LL x)
{
return x >= 0 ? x : -x;
}
int n, l;
LL r;
int f[maxn], range[maxn];
bool vis[maxn];
int find_baba(int x)
{
return x == f[x] ? x : f[x] = find_baba(f[x]);
}
void uni(int a, int b)
{
int fa = find_baba(a);
int fb = find_baba(b);
if(fa != fb)
{
f[fb] = fa;
range[fa] += range[fb];
}
}
void work()
{
s.clear();
int st = 0;
int a, b;
for(int i = 0; i < n; i++)
{
while(ABS(p[i].x - p[st].x) > l)
{
s.erase(make_pair(p[st].y, st));
st++;
}
it = s.insert(make_pair(p[i].y, i)).first; //返回插入元素地址
if(it != s.begin())
{
it--;
if(ABS(p[i].y - (it->first)) <= l)
{
a = i;
b = it->second;
uni(a, b);
}
it++;
}
it++;
if(it != s.end() && ABS(p[i].y - (it->first)) <= l)
{
a = i;
b = it->second;
uni(a, b);
}
}
}
int main()
{
// freopen("3521.in", "r", stdin);
while(~scanf("%d%lld%d", &n, &r, &l))
{
fill(range, range + n, 1);
l /= 2;
for(int i = 0; i < n; i++)
f[i] = i;
for(int i = 0; i < n; i++)
scanf("%lld%lld", &p[i].x, &p[i].y);
sort(p, p + n);
scanf("%lld%lld", &c.x, &c.y);
work();
int ans = 0;
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++)
{
if((p[i] - c).len2() <= r * r)
{
int ba = find_baba(i);
if(!vis[ba])
{
ans += range[ba];
vis[ba] = true;
}
}
}
printf("%d\n", ans);
}
return 0;
}