


题目链接
穿过园
题目大意
平面上又许多不相交的园包围着点,每回询问两个点 a ,b 询问从a到b至少穿过多少个圆。
思路
最开始想到暴力的解法,也就是对每个点进行遍历,看其是否在园内,并将此点在多少个园内的数量记录在一个数组cnt中,然后记录a和b在相同园内的数量(假设记作k),拿cnt[a]+cnt[b]-2*k即为答案,这样做的时间复杂度过大无法通过题目要求。
听课后学会了一种压位的做法,即用bitset存储这个点对于各个园的状态,在园内为0,在园外为1,然后将两个点的二进制位数亦或,此时二进制中1的个数即为所求答案。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <bitset>
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1010;
int n, m, Q;
PII p[N], c[N];
int r[N];
bitset<N> st[N];
LL sqr(LL x)
{
return x * x;
}
int check(int a, int b)
{
LL dx = p[a].x - c[b].x;
LL dy = p[a].y - c[b].y;
if (sqr(dx) + sqr(dy) > sqr(r[b])) return 1;
return 0;
}
int main()
{
scanf("%d%d%d", &n, &m, &Q);
for (int i = 1; i <= n; i ++ ) scanf("%d%d", &p[i].x, &p[i].y);
for (int i = 0; i < m; i ++ )
scanf("%d%d%d", &r[i], &c[i].x, &c[i].y);
for (int i = 1; i <= n; i ++ )
for (int j = 0; j < m; j ++ )
st[i][j] = check(i, j);
while (Q -- )
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", (st[a] ^ st[b]).count());
}
return 0;
}
这篇博客探讨了一道算法题目,涉及平面上的点和不相交圆。文章介绍了如何使用暴力方法和优化策略(如位运算和压位)来解决从一点到另一点穿越最少圆的问题。优化后的算法大大提高了效率,通过位运算计算两点在各圆内外状态的异或结果,得到穿越圆的数量。此外,文章还提及了利用倍增LCA(最近公共祖先)的解决方案,但未展开详细说明。

被折叠的 条评论
为什么被折叠?



