F 小红的线下查询

首先观察到是数点问题,那就想几维数点、扫描线。 观察可得每个点坐标可以转换成 两个维度的值,而我们查询的区间是 下部分的 的点有多少,那么我们就可以把 变成一维,用扫描线的思想查询比 小的值加入答案就行了。

#include<bits/stdc++.h>
#define int long long
using namespace std;

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int n, q;
    cin >> n >> q;
    
    vector<array<int, 2>> a(n), b(q);
    vector<int> c;
    vector<int> ans(q, 0);
    for (int i = 0; i < n; i++) {
        cin >> a[i][0] >> a[i][1];
        c.push_back(a[i][0] + a[i][1]);
        c.push_back(a[i][1] - a[i][0]);
    }
    for (int i = 0; i < q; i++) {
        cin >> b[i][0] >> b[i][1];
        c.push_back(b[i][0]);
        c.push_back(b[i][1]);
    }
    c.push_back(-1e18);
    sort(c.begin(), c.end());
    c.erase(unique(c.begin(), c.end()), c.end());
    int m = c.size();

    sort(a.begin(), a.end(), [](const array<int, 2> &a, const array<int, 2> &b){
        return a[0] + a[1] < b[0] + b[1];
    });
    
    vector<array<int, 4>> L;
    for (auto [x, y]: a) {
        int k2 = x + y, k1 = y - x;
        k2 = lower_bound(c.begin(), c.end(), k2) - c.begin();
        k1 = lower_bound(c.begin(), c.end(), k1) - c.begin();
        L.push_back({k2, k1, -2, 0});
    }
    
    for (int i = 0; i < q; i++) {
        int k2 = b[i][1], k1 = b[i][0];
        k2 = lower_bound(c.begin(), c.end(), k2) - c.begin();
        k1 = lower_bound(c.begin(), c.end(), k1) - c.begin();
        L.push_back({k2, k1, 1, i});
    }
    
    sort(L.begin(), L.end(), [](const array<int, 4> &a, const array<int, 4> &b){
        if (a[0] == b[0]) return a[2] > b[2];
        return a[0] < b[0];
    });
    
    vector<int> tr(m << 2);
    
    auto update = [&](auto &self, int l, int r, int x, int p) {
        if (l == r) {
            tr[p]++;
            return;
        }
        int mid = l + r >> 1;
        if (x <= mid) self(self, l, mid, x, p << 1);
        else self(self, mid + 1, r, x, p << 1 | 1);
        tr[p] = tr[p << 1] + tr[p << 1 | 1];
    };

    auto query = [&](auto &self, int l, int r, int ql, int qr, int p) {
        if (ql <= l && qr >= r) return tr[p];
        int mid = l + r >> 1, ans = 0;
        if (ql <= mid) ans += self(self, l, mid, ql, qr, p << 1);
        if (qr > mid) ans += self(self, mid + 1, r, ql, qr, p << 1 | 1);
        return ans;
    };
    
    for (auto[k2, k1, op, idx]: L) {
        if (op == -2) update(update, 1, m, k1, 1);
        else ans[idx] += query(query, 1, m, 1, max(1ll, k1 - 1), 1);
    }
    
    for (int i = 0; i < q; i++) cout << ans[i] << "\n";
    
    return 0;
}