把整个坐标系想象成一个大圈,编号就给他当m,先把能括住每个点的最小圈记录下来,再把能括住某个圈的最小圈记录下来,这样每个点都有父圈,每个小圈也有父圈。这样每次询问a和b的距离,可以通过计数经过的父圈节点来计算距离。怎么快速计算到父圈的距离呢?通过创建st表,st[i][j]表示编号i点经过2**j的父圈到达的父父父....圈编号。但是k=10**5次方,算法超时。有待改进!!!!!!!!!!!!!
from collections import defaultdict
def dfs(node, f):
st[node][0] = f
depth[node] = depth[f]+1
for j in range(1, 12):
st[node][j] = st[ st[node][j-1] ][j-1]
for nex in edge[node]:
dfs(nex, node)
n, m, k = map(int, input().split())
points = []
cir = []
for _ in range(n):
x, y = map(int, input().split())
points.append([x, y])
for _ in range(m):
r, x, y = map(int, input().split())
cir.append([r, x, y])
cir.sort()
# 圆形半径是从小到大排序, 所以可以记录能包括某个点的最小圆
min_c = [m]*n
for i in range(n):
x, y = points[i]
for j in range(m):
r, x1, y1 = cir[j]
if (x1-x)**2 + (y1-y)**2 < r**2:
min_c[i] = j
break
# 给圆形建立树,大圆扩小圆
# edge[i] 表示编号i的子节点
edge = defaultdict(list)
for i in range(m):
r1, x1, y1 = cir[i]
b = True
for j in range(i+1, m):
r2, x2, y2 = cir[j]
#print(i, cir[j] )
if (x1-x2)**2 + (y1-y2)**2 < r2**2:
edge[j].append(i)
b = False
break
if b: edge[m].append(i)
#print(edge)
# 建立st表,st[i][j]表示从i号圈向外走2**j个圈,的编号
st = [ [0]*12 for _ in range(m+1) ]
depth = [0]*(m+1)
depth[m] = 0
dfs(m, m)
for _ in range(k):
a, b = map(int, input().split())
a, b = min_c[a-1], min_c[b-1]
if a == b:
print(0)
continue
ans = 0
d1, d2 = depth[a], depth[b]
# 让a节点更深,方便处理
if d1 < d2:
d1, d2 = d2, d1
a, b = b, a
# 让a节点到达b节点的深度
ans += d1-d2
for i in range(11, -1, -1):
if depth[st[a][i]] >= d2:
a = st[a][i]
if a == b:
print(ans)
continue
# a与b不在同一个圈中,找到LCA
for i in range(11, -1, -1):
if st[a][i] != st[b][i]:
a = st[a][i]
b = st[b][i]
ans += 2**(i+1)
ans += 2
print(ans)