CF1569D Inconvenient Pairs
CF1569D Inconvenient Pairs
一个被我这种菜鸡秒掉的 \(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;
}
看不见我看不见我看不见我