HDU - 5618 CDQ分治 + 树状数组

来源:互联网 发布:双喜软件怎么样 编辑:程序博客网 时间:2024/05/14 09:31

题意:

给出n个有序对(a,,b,c),对于每个(ai,bi,ci)找到满足aj <=ai,bj<=bi,cj<=ci的有序对有多少个。

思路:

典型的三维偏序问题,可以用CDQ分治来解决。
首先将有序对按照a的大小排序,这样对区间[L,R)进行分治的时候就可以默认左半部分[L,M)的a要小于等于右半部份[M,R)的a。按照CDQ分治的思想,先递归处理左右两个部分的子问题,然后处理左半部分对于右半部份的影响,就这题来说,就是对左右两部分按照b的大小排序,按照归并排序的写法先进入临时数组tmp的有序对b一定不大于之后进的。那么现在关键是处理c,因为有c存在不能直接计数,注意到所有数字的大小只有1e5,这时候考虑用树状数组求和来统计c的个数,就如同求逆序对的作法一样。对于左半部分的每一个有序对在来更新树状数组,右半部份的每个有序对来查询树状数组,从而计数。
这题还有几个地方需要注意:
1.定义Query大小关系的时候,要记得包括小于等于的情况。
2.排序的时候不能只按照a的大小排序,还要按照先b后c确定优先级,因为这样才能保证右边区间的有序对能找到所有比优先级他小的。
3.按照上面的做法,如果有m个完全一样的有序对(a,b,c),这m个有序对所求的结果受到位置的影响并不一样,因为排在后面的可以统计前面的,而前面的却没有统计后面的,所以一开始排序排在m个中最后的那个有序对才是这m个有序对共同的答案。
4.记得在每一次的分治都要清空树状数组。

代码:

#include <bits/stdc++.h>using namespace std;const int MAXN = 1e5 + 10;const int MAXC = 1e5 + 10;const int MAXQ = MAXN;int maxc;struct BIT {    int C[MAXC];    int lowbit(int x) {        return x & -x;    }    void add(int x, int y) {        while (x <= MAXC) {            C[x] += y;            x += lowbit(x);        }    }    int sum(int x) {        int res = 0;        while (x) {            res += C[x];            x -= lowbit(x);        }        return res;    }     void clr(int x){         while (x <= MAXC) {             if (C[x]) C[x] = 0; else break;             x += lowbit(x);          }     }}bit;struct Query {    int id, b, c;    bool operator < (const Query &rhs) const {        return b == rhs.b ? c <= rhs.c : b < rhs.b;    // 优先级一定要考虑到等于的情况    }}que[MAXQ], tmp[MAXQ];int ans[MAXN];void cdq(int l, int r) {    if (r - l <= 1) return;    int m = (l + r) >> 1;    cdq(l, m); cdq(m, r);    int p = l, q = m, cnt = 0;    while (p < m && q < r) {        if (que[p] < que[q]) {            bit.add(que[p].c, 1);            tmp[cnt++] = que[p++];        }        else {            ans[que[q].id] += bit.sum(que[q].c);            tmp[cnt++] = que[q++];        }    }    while (p < m) tmp[cnt++] = que[p++];    while (q < r) {        ans[que[q].id] += bit.sum(que[q].c);        tmp[cnt++] = que[q++];    }    for (int i = 0; i < cnt; i++) {        bit.clr(tmp[i].c);        que[i + l] = tmp[i];    }}struct node {    int id, a, b, c;    bool operator < (const node &rhs) const {        return a == rhs.a ? (b == rhs.b ? c < rhs.c : b < rhs.b) : a < rhs.a;   // 考虑位置因素,要按照先a再b后c的优先级排序    }}arr[MAXN];int main() {    //freopen("in.txt", "r", stdin);    int T;    scanf("%d", &T);    while (T--) {        int n;        scanf("%d", &n);        for (int i = 0; i < n; i++) {            scanf("%d%d%d", &arr[i].a, &arr[i].b, &arr[i].c);            arr[i].id = i;        }        sort (arr, arr + n);        maxc = 0;        for (int i = 0; i < n; i++) {            que[i] = (Query) {arr[i].id, arr[i].b, arr[i].c};            maxc = max(maxc, arr[i].c);        }        memset(ans, 0, sizeof(ans));        cdq(0, n);        for (int i = n - 1; i >= 0; i--) {            if (arr[i].a == arr[i + 1].a && arr[i].b == arr[i + 1].b && arr[i].c == arr[i + 1].c)                ans[arr[i].id] = ans[arr[i + 1].id];        // 倒着更新相同有序对的答案        }        for (int i = 0; i < n; i++)            printf("%d\n", ans[i]);    }    return 0;}


0 0