一道逆序对题

CF1915F

https://codeforces.com/contest/1915/problem/F

先了解什么是逆序对 https://www.luogu.com.cn/problem/P1908 即i < j但a[i] > a[j]的数对。
求解的方法:树状数组求解。
树状数组维护的其实就是一个区间内比他大并且比他先出现的值,每次查询的范围就是在原数组的下标之前。
我们可以先将数组按照第一关键字为值,第二关键字为下标数从大到小排序,一是离散化处理,二是为了让值相同,下标大的先出现,这样在统计的过程中,就不会多统计。

现在回到本题。
手画一下,当一个区间[l, r], [x, y],是完全包含的关系的时候,就是一种合法的情况。先将所有l排序,这时的顺序是l从小到大的顺序,然后对该顺序下的r统计逆序对(这里面的思维有点绕,需要理清楚)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int mod = 998244353, INF = 1 << 30;
const int N = 2e5 + 10;
PII a[N], b[N];
LL c[N];
int n;


int lowbit(int x) {
    return x & (-x);
}

void update(int p, LL k) {
    for (; p <= n; p += lowbit(p)) {
        c[p] += k;
    }
}

LL ask(int p) {
    LL ans = 0;
    while (p) {
        ans += c[p];
        p -= lowbit(p);
    }
    return ans;
}

void solve() {
    cin >> n;
    vector<int> B(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i].first;
        a[i].second = i;
        cin >> B[i];
        c[i] = 0;
    } 
    sort(a + 1, a + 1 + n);
    LL ans = 0;
    for (int i = 1; i <= n; i ++) {
        b[i].first = B[a[i].second];
        b[i].second = i;
    }
    sort(b + 1, b + 1 + n, greater<PII>());
    for (int i = 1; i <= n; i ++) {
        ans += ask(b[i].second - 1);
        update(b[i].second, 1);
    }
    cout << ans << endl;
}


int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int t = 1;
    cin >> t;
    while(t --) solve();
    return 0;
}
posted @ 2024-01-15 20:21  lu1no  阅读(5)  评论(0编辑  收藏  举报