题目链接
穿过园
题目大意
平面上又许多不相交的园包围着点,每回询问两个点 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;
}