• AtCoder Beginner Contest 231 F Jealous Two(二维偏序)


    F - Jealous Two

    题目大意:

    给出 \(n\) 个点 \((a_i, b_i)\) ,问满足下列条件的 \((i, j)\) 有多少对:

    • \(1 \leq i, j \leq n\)
    • \(a_i \geq a_j\) && \(b_i \leq b_j\)
    思路:

    典型的二维偏序问题。

    考虑类似离散化后用树状数组求逆序对的方法。那么我们要解决的问题就是如何处理等于关系。

    我们以 \(b\) 作为关键字排序,然后逆序采用双指针,对于当前的下标 \(i\),将 \(b\) 相同的点加入到树状数组中(比 \(val[i].b\) 小的在之前加过了),然后我们要求有多少个点 \(val[j].a\) 满足 \(val[i].a \geq val[j].a\) ,那么就是求(离散化后)有多少个点在 \([0, val[i].a]\) 上。

    for (int i = n, j = n; i >= 1; i--) {
        while (j >= 1 && val[i].b == val[j].b) {
            fen.add(getid(val[j].a, ta), 1);
            j--;
        }
        ll tmp = fen.sum(getid(val[i].a, ta));
        ans += tmp;
    }
    

    我们也可以顺序的采用双指针,对于当前的下标 \(i\),不同的是计算点的数量时,求(离散化后)有多少个点在 \([val[i].a, n]\) 上。

    for (int i = 1, j = 1; i <= n; i++) {
        while (j <= n && val[j].b == val[i].b) {
            fen.add(getid(val[j].a, ta), 1);
            j++;
        }
        ll tmp = fen.rangeSum(getid(val[i].a, ta) - 1, n);
        ans += tmp;
    }
    
    Code:
    template <typename T>
    struct Fenwick {
        const int n;
        vector<T> a;
        Fenwick(int n) : n(n), a(n + 1) {}
        void add(int x, T v) {
            for (int i = x; i <= n; i += i & -i) {
                a[i] += v;
            }
        }
        T sum(int x) {
            T ans = 0;
            for (int i = x; i > 0; i -= i & -i) {
                ans += a[i];
            }
            return ans;
        }
        T rangeSum(int l, int r) {
            return sum(r) - sum(l);
        }
    };
     
    struct Node {
        int a;
        int b;
        bool operator<(const Node &t) const {
            return b < t.b;
        }
    };
     
    int main() {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int n;
        cin >> n;
        Fenwick<ll> fen(n);
        vector<Node> val(n + 1);
        vector<int> ta, tb;
     
        auto getid = [&](int x, vector<int> &t) {
            return lower_bound(t.begin(), t.end(), x) - t.begin() + 1;
        };
     
        for (int i = 1; i <= n; i++) {
            cin >> val[i].a;
            ta.emplace_back(val[i].a);
        }
        for (int i = 1; i <= n; i++) {
            cin >> val[i].b;
            tb.emplace_back(val[i].b);
        }
     
        sort(ta.begin(), ta.end());
        ta.erase(unique(ta.begin(), ta.end()), ta.end());
        sort(tb.begin(), tb.end());
        tb.erase(unique(tb.begin(), tb.end()), tb.end());
     
        sort(val.begin() + 1, val.end());
        ll ans = 0;
        for (int i = n, j = n; i >= 1; i--) {
            while (j >= 1 && val[i].b == val[j].b) {
                fen.add(getid(val[j].a, ta), 1);
                j--;
            }
            ll tmp = fen.sum(getid(val[i].a, ta));
            ans += tmp;
        }
        cout << ans << "\n";
        return 0;
    }
    
  • 相关阅读:
    sql: update from
    sql: 查询,select
    english: 遭遇
    sql: sybase与oracle中insert into select和select into的用法
    lcd参数解释及刷新率计算,LCD时序
    Camera Binning Mode
    页框分配器【转】
    (一)洞悉linux下的Netfilter&iptables:什么是Netfilter?
    网络中的NAT模式
    组播、单播、多播
  • 原文地址:https://www.cnblogs.com/Nepenthe8/p/16062899.html
Copyright © 2020-2023  润新知