zoukankan      html  css  js  c++  java
  • 【每日一题】39. Contest(树状数组 / 容斥分治)

    补题链接:Here

    算法涉及:树状数组、CDQ分治

    n支队伍一共参加了三场比赛。
    一支队伍x认为自己比另一支队伍y强当且仅当x在至少一场比赛中比y的排名高。
    求有多少组(x,y),使得x自己觉得比y强,y自己也觉得比x强。
    (x, y), (y, x)算一组。


    【方案一】树状数组求逆序数

    我们转换问题,x要比y最少一门排名高,y也对x同样如此。
    那么就变成了,x有2门比y排名高,或者x2门比y排名低。因为排名不可能相同。
    那么题目就变成了求逆序数问题,可以按照某一门排名去放另外一门成绩,求到的逆序数就是只看这两门的情况。
    那么对于合理的x,y找到排名高,和排名低各一次,直接把答案除以2。

    using ll = long long;
    const int N = 2e5 + 10;
    int a[N], b[N], c[N];
    int tmp[N], sum[N];
    int n;
    int lowbit(int x) {return x & (-x);}
    void add(int p, int val) {
        for (; p <= n; p += lowbit(p))sum[p] += val;
    }
    ll query(int i) {
        ll ans = 0;
        for (; i; i -= lowbit(i))ans += sum[i];
        return ans;
    }
    ll check(int a[], int b[]) {
        memset(sum, 0, sizeof(sum));
        for (int i = 1; i <= n; ++i)tmp[a[i]] = b[i];
        ll ans = 0;
        for (int i = 1; i <= n; ++i) {
            ans += query(n) - query(tmp[i]);
            add(tmp[i], 1);
        }
        return ans;
    }
    void solve() {
        cin >> n;
        for (int i = 1; i <= n; ++i)cin >> a[i] >> b[i] >> c[i];
        cout << (check(a, b) + check(a, c) + check(b, c)) / 2;
    }
    

    【方案二】容斥思想

    容斥思想, 不考虑任何限制,总共有 (p =n(n - 1) / 2) 种组合
    我们要求题目给的限制方案不好求,逆向思维求不符合的情况
    显然不符合的情况是一个三维偏序 (a[i] > a[j], b[i] > b[j], c[i] > c[j])

    三维偏序问题可以用 cdq 分治去解决,这里就不赘述了
    得到三维偏序的方案为 res
    那么答案就是 p - res

    using ll = long long;
    struct node {
        int x, y, z;
        bool operator < (const node &s) {
            return x < s.x;
        }
    } a[200005], b[200005];
    ll p;
    ll t[200005];
    int lowbit(int x) {
        return x & (-x);
    }
    
    void add(int x, int y) {
        while (x < 200005) {
            t[x] += y;
            x += lowbit(x);
        }
    }
    
    ll sum(int x) {
        ll ans = 0;
        while (x) {
            ans += t[x];
            x -= lowbit(x);
        }
        return ans;
    }
    
    void cdq(int l, int r) {
        if (l == r) return ;
        int mid = l + r >> 1;
        cdq(l, mid); cdq(mid + 1, r);
        int L = l, R = mid + 1, tot = l;
        while (L <= mid && R <= r) {
            if (a[L].y <= a[R].y) add(a[L].z, 1), b[tot++] = a[L++];
            else p -= sum(a[R].z), b[tot++] = a[R++];
        }
        while (L <= mid) {
            add(a[L].z, 1);
            b[tot++] = a[L++];
        }
        while (R <= r) {
            p -= sum(a[R].z);
            b[tot++] = a[R++];
        }
        for (int i = l; i <= mid; i++) add(a[i].z, -1);
        for (int i = l; i <= r; i++) a[i] = b[i];
    }
    int main() {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> a[i].x >> a[i].y >> a[i].z;
        }
        p = 1LL * n * (n - 1) / 2;
        sort(a + 1, a + 1 + n);
        cdq(1, n);
        cout << p << "
    ";
        return 0;
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    基础
    基础
    基础
    基础
    基础
    基础
    基础
    基础
    Gym102361A Angle Beats(直角三角形 计算几何)题解
    Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解
  • 原文地址:https://www.cnblogs.com/RioTian/p/14845259.html
Copyright © 2011-2022 走看看