Inconvenient Pairs
题目链接:luogu CF1569D
题目大意
有一个方形网格,然后只有一些竖着的直线和横着的直线是可以走的(会给出它们的 x 坐标或 y 坐标)。
然后会给你一些点,保证点在可以走的位置上。
然后问你有多少个点对之间的最短距离大于它们的哈密顿距离。
思路
你考虑怎样的点是会出现那样的情况的。
首先如果一个点在交叉路口,那有它的点对就不可能。
然后你会发现满足的点对一遍都是一个维度在路口上但是不在同一个路口,另一个维度就不再路口上,而且如果你拿另一个维度的路口去把这个维度分成几段,那它们是在同一段上。
然后你就随便用点东西统计一下即可。
然后记得要从两个维度来分别统计。
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
struct node {
int x, y;
int xx, yy;
int xp, yp;
}a[300005];
int t, n, m, k;
int xx[300005], yy[300005];
int pl[300005], nm[300005];
int lstnm[300005];
ll ans;
bool cmp1(node x, node y) {
return x.x < y.x;
}
bool cmp2(node x, node y) {
return x.y < y.y;
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= n; i++) scanf("%d", &xx[i]);
for (int i = 1; i <= m; i++) scanf("%d", &yy[i]);
for (int i = 1; i <= k; i++) {
scanf("%d %d", &a[i].x, &a[i].y);
if (xx[lower_bound(xx + 1, xx + n + 1, a[i].x) - xx] == a[i].x) a[i].xx = 1, a[i].xp = 3e5 + 1;
else a[i].xx = 0, a[i].xp = lower_bound(xx + 1, xx + n + 1, a[i].x) - xx;
if (yy[lower_bound(yy + 1, yy + m + 1, a[i].y) - yy] == a[i].y) a[i].yy = 1, a[i].yp = 3e5 + 1;
else a[i].yy = 0, a[i].yp = lower_bound(yy + 1, yy + m + 1, a[i].y) - yy;
// printf("%d %d %d %d\n", a[i].xx, a[i].xp, a[i].yy, a[i].yp);
}
sort(a + 1, a + k + 1, cmp1);
for (int i = 1; i <= k; i++) {
int ii = i;
pl[0] = 0;
nm[a[i].yp] += !a[i].yy; if (nm[a[i].yp] == 1) pl[++pl[0]] = a[i].yp;
while (i < k && a[i + 1].x == a[i].x) {i++, nm[a[i].yp] += !a[i].yy; if (nm[a[i].yp] == 1) pl[++pl[0]] = a[i].yp;}
for (int j = 1; j <= pl[0]; j++) {
ans += 1ll * lstnm[pl[j]] * nm[pl[j]];
lstnm[pl[j]] += nm[pl[j]];
}
for (int j = ii; j <= i; j++) nm[a[j].yp] = 0;
}
for (int i = 1; i <= k; i++)
lstnm[a[i].yp] = 0;
sort(a + 1, a + k + 1, cmp2);
for (int i = 1; i <= k; i++) {
int ii = i;
pl[0] = 0;
nm[a[i].xp] += !a[i].xx; if (nm[a[i].xp] == 1) pl[++pl[0]] = a[i].xp;
while (i < k && a[i + 1].y == a[i].y) {i++, nm[a[i].xp] += !a[i].xx; if (nm[a[i].xp] == 1) pl[++pl[0]] = a[i].xp;}
for (int j = 1; j <= pl[0]; j++) {
ans += 1ll * lstnm[pl[j]] * nm[pl[j]];
lstnm[pl[j]] += nm[pl[j]];
}
for (int j = ii; j <= i; j++) nm[a[j].xp] = 0;
}
for (int i = 1; i <= k; i++)
lstnm[a[i].xp] = 0;
printf("%lld\n", ans);
ans = 0;
}
return 0;
}