一个被我这种菜鸡秒掉的 \(D\) 题.
起初一看, 似乎可做.
这些道路把行和列分成不同的区块, 我们试试把这些区块分开来, 哦, 内存不够, 那没事了.
那么我们来想一想, 什么情况下两个点会是不方便的, 似乎只有在一个区块的对边且不在角上的时候, 两个不方便的点之间要么没有竖线, 要么没有横线, 嗯, 好像是对的.
那我们就二分查找一波, 我不会用 \(lower\_bound\) , 而且这样好像得枚举点, 会 \(TLE\) .
那么我们就尝试利用路来计算贡献, 而不是点, 因为枚举点的话一定是会 \(T\) 的.
我们想一下, 如果两个点有贡献, 那么这两个点与路的关系会是什么样子的?
如果这两个点中间没有水平的路, 那么它们一定介于两条竖直的路中间, 且这两条路中间没有任何竖直的路.
是的.
然后我们发现任何这样的两条路之间的点都会产生贡献, 只要它们不在同一条路上.
竖直与水平同理.
所以我们先后把水平和竖直的路排序, 计算每两条路之间的贡献, 顺便记录这两条路之间出现在同一条路上的点, 减掉它们的贡献.
码完之后, 提交, \(TLE\) .
我一猜就是 \(unordered\_map\) 的锅, 本来是为了方便, 结果 \(T\) 了.
由于值域不大, 我们可以直接开数组, 然后 \(clear\) 的时候开个栈.
没想到我连手写栈都写挂了...日...
\(STL\) 万岁!
\(code:\)
#include <bits/stdc++.h> using namespace std; typedef long long ll; int read() { int x = 0, f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } return x * f; } const int N = 3e5 + 5; int n, m, k, rx[N], ry[N], sumx[N], sumy[N], mp[1000005]; ll ans; stack <int> stk; struct Node { int x, y; } pp[N]; bool cmp1(Node a, Node b) { return a.x < b.x; } bool cmp2(Node a, Node b) { return a.y < b.y; } void add(int p) { stk.push(p); } void clear() { while (stk.size()) { mp[stk.top()] = 0; stk.pop(); } } int main() { int T = read(); while (T--) { n = read(), m = read(), k = read(); ans = 0; clear(); memset(sumx, 0, sizeof(int) * (n + 2)); memset(sumy, 0, sizeof(int) * (m + 2)); for (int i = 1; i <= n; i++) rx[i] = read(); rx[n + 1] = 1e6 + 5; for (int i = 1; i <= m; i++) ry[i] = read(); ry[m + 1] = 1e6 + 5; for (int i = 1; i <= k; i++) pp[i].x = read(), pp[i].y = read(); sort(rx + 1, rx + n + 1); sort(ry + 1, ry + m + 1); sort(pp + 1, pp + k + 1, cmp1); int num = 1; for (int i = 1; i <= k; i++) { while (pp[i].x > rx[num] && num <= n) { clear(); num++; } if (pp[i].x != rx[num]) { add(pp[i].y); mp[pp[i].y]++; ans -= mp[pp[i].y] - 1; sumx[num]++; } } sort(pp + 1, pp + k + 1, cmp2); num = 1; clear(); for (int i = 1; i <= k; i++) { while (pp[i].y > ry[num] && num <= m) { clear(); num++; } if (pp[i].y != ry[num]) { add(pp[i].x); mp[pp[i].x]++; ans -= mp[pp[i].x] - 1; sumy[num]++; } } for (int i = 1; i <= n + 1; i++) ans += 1ll * sumx[i] * (sumx[i] - 1) >> 1; for (int i = 1; i <= m + 1; i++) ans += 1ll * sumy[i] * (sumy[i] - 1) >> 1; printf("%lld\n", ans); } return 0; }