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;
}
上一篇:[算法总结] LIS最长上升子序列1


下一篇:7.23日算法结记