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
- HDU 5618 (CDQ分治 树状数组)
- HDU - 5618 CDQ分治 + 树状数组
- HDU 5126 stars cdq分治+树状数组
- hdu 5126 stars ( CDQ分治 + 树状数组)
- HDU 4742 (CDQ分治 树状数组)
- HDU 5324 (CDQ分治 树状数组)
- BZOJ1176【CDQ分治】【树状数组】
- hdu 5324 Boring Class cdq分治+树状数组+离散化
- hdu 4417 Super Mario(主席树||cdq分治+树状数组)
- 【HDU】5126 stars cdq分治套cdq分治套树状数组
- HDU 5618 Jam's problem again (cdq分治+树状数组)
- HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
- Hdu 5618 CDQ分治
- hdu 5324 Boring Class(树状数组+笛卡尔树 | 树状数组+cdq分治)
- [BZOJ1176][Balkan2007]Mokia && CDQ分治+树状数组
- COGS 577 蝗灾 cdq分治+树状数组
- BZOJ_P1176 [Balkan2007]Mokia(CDQ分治+树状数组)
- BZOJ_P3262 陌上花开(CDQ分治+树状数组)
- 懒虫小鑫(g++)
- 蓝牙核心技术概述(二):蓝牙使用场景
- Android 热修复之三大流派
- 图片验证码生成
- Linux 关闭防火墙
- HDU - 5618 CDQ分治 + 树状数组
- jsp隐式对象
- Strust2学习之Action、Result知识要点
- 人事管理系统实现(五)
- leetcode -- 496. Next Greater Element I 【栈】
- Two classes have the same XML type
- 100行C代码终端打印树形结构
- SDUTOJ 2173 数据结构实验之求二叉树后序遍历和层次遍历
- Radio+不可滑动的viewpager实现底部导航栏