hdu5618 (三维偏序,cdq分治)
给定空间中的n个点,问每个点有多少个点小于等于自己。
先来分析简单的二维的情况,那么只要将x坐标排序,那么这样的问题就可以划分为两个子问题,,这样的分治有一个特点,即前一个子问题的解决是独立的,而后一个子问题的解决依赖于前一个子问题,即用前一个子问题来解决后一个子问题,而不是合并。 这就是cdq分治。
具体的代码如下。
void cdq(int l, int r){if(l==r) return;int m = (l+r)>>1;cdq(l,m);cdq(m+1,r);//按y进行排序,那么问题就变成两个y递增的集合,//后一个集合中的每个y在前一个集合中有多少个y小于等于它sort(a+l,a+m+1,cmp);sort(a+m+1,a+r+1,cmp);int j = l;for(int i=m+1;i<=r;++i){for(;j<=m;&&a[j].y<=a[i].y;++j);a[i].sum += j - l;} }
而三维的问题由于多了一维,不能使用线性的方法 了。
我们可以用树状数组来维护z这一维,具体的代码如下。
并且最后要注意坐标相等的情况。
第一份代码,因为cdq里面又嵌套了sort,所以时间复杂度是O(n*logn*logn)
#include <stdio.h> #include <math.h> #include <algorithm> #include <iostream> #include <string.h> using namespace std; struct Point{int x,y,z;int id;int sum;Point(){}Point(int x, int y):x(x),y(y){}bool operator<(const Point&rhs)const{if(x!=rhs.x) return x < rhs.x;if(y!=rhs.y) return y < rhs.y;return z < rhs.z;}bool operator==(const Point &rhs)const{return x==rhs.x && y==rhs.y && z==rhs.z;} }; bool cmp(const Point &lhs, const Point &rhs){if(lhs.y!=rhs.y) return lhs.y <rhs.y;return lhs.z <rhs.z; } const int N = 100000 + 10; Point a[N]; class BIT{ public:int sum[N];int n;void init(){n = 100000;memset(sum,0,sizeof(sum));}int lowbit(int x){return x & (-x);}int modify(int x, int val){while(x<=n){sum[x] += val;x += lowbit(x);}}int getSum(int x){int ret= 0;while(x>0){ret += sum[x];x -= lowbit(x);}return ret;} }bit;void cdq(int l, int r){if(l==r)return;int m = (l+r)>>1;cdq(l,m);cdq(m+1,r);sort(a+l,a+m+1,cmp);sort(a+m+1,a+r+1,cmp);int j = l;for(int i=m+1;i<=r;++i){for(;j<=m &&a[j].y<=a[i].y;++j)bit.modify(a[j].z,1);a[i].sum += bit.getSum(a[i].z);}for(int i=l; i<j; ++i)bit.modify(a[i].z,-1);}int ans[N]; int main(){int t,n;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=0;i<n;++i){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].id = i; a[i].sum=0;}sort(a,a+n);bit.init();cdq(0,n-1);sort(a,a+n);for(int i=0;i<n;){int j = i + 1;int tmp = a[i].sum;//分治时,坐标相等的时候,//排在前边的坐标不能使用后边的坐标更新自己,所以要在这里处理一下for(;j<n &&a[i]==a[j];++j) tmp = max(tmp,a[j].sum);for(int k=i;k<j;++k) ans[a[k].id] = tmp;i = j;}for(int i=0;i<n;++i)printf("%d\n",ans[i]);}return 0; }
第二份代码,在cdq分治的最后加入归并排序,是的复杂度变成O(n*logn)
#include <stdio.h> #include <math.h> #include <algorithm> #include <iostream> #include <string.h> using namespace std; struct Point{int x,y,z;int id;int sum;Point(){}Point(int x, int y):x(x),y(y){}bool operator<(const Point&rhs)const{if(x!=rhs.x) return x < rhs.x;if(y!=rhs.y) return y < rhs.y;return z < rhs.z;}bool operator==(const Point &rhs)const{return x==rhs.x && y==rhs.y && z==rhs.z;} }; bool cmp(const Point &lhs, const Point &rhs){if(lhs.y!=rhs.y) return lhs.y <rhs.y;return lhs.z <rhs.z; } const int N = 100000 + 10; Point a[N]; class BIT{ public:int sum[N];int n;void init(){n = 100000;memset(sum,0,sizeof(sum));}int lowbit(int x){return x & (-x);}int modify(int x, int val){while(x<=n){sum[x] += val;x += lowbit(x);}}int getSum(int x){int ret= 0;while(x>0){ret += sum[x];x -= lowbit(x);}return ret;} }bit;Point tmp[N]; void cdq(int l, int r){if(l==r)return;int m = (l+r)>>1;cdq(l,m);cdq(m+1,r);//sort(a+l,a+m+1,cmp);//sort(a+m+1,a+r+1,cmp);int j = l;for(int i=m+1;i<=r;++i){for(;j<=m &&a[j].y<=a[i].y;++j)bit.modify(a[j].z,1);a[i].sum += bit.getSum(a[i].z);}for(int i=l; i<j; ++i)bit.modify(a[i].z,-1);//归并排序, 这样就不需要上面的sort了int i = l ;j = m+1;for(int k=l;k<=r;++k){if(i>m) tmp[k] = a[j++];else if(j>r) tmp[k] = a[i++];else if(a[i].y < a[j].y) tmp[k] = a[i++];else tmp[k] = a[j++];}for(int k=l;k<=r;++k)a[k] = tmp[k];}int ans[N]; int main(){int t,n;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=0;i<n;++i){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].id = i; a[i].sum=0;}sort(a,a+n);bit.init();cdq(0,n-1);sort(a,a+n);for(int i=0;i<n;){int j = i + 1;int tmp = a[i].sum;//分治时,坐标相等的时候,//排在前边的坐标不能使用后边的坐标更新自己,所以要在这里处理一下for(;j<n &&a[i]==a[j];++j) tmp = max(tmp,a[j].sum);for(int k=i;k<j;++k) ans[a[k].id] = tmp;i = j;}for(int i=0;i<n;++i)printf("%d\n",ans[i]);}return 0; }
具体算法流程如下:
1.将整个操作序列分为两个长度相等的部分(分)
2.递归处理前一部分的子问题(治1)
3.计算前一部分的子问题中的修改操作对后一部分子问题的影响(治2)
4.递归处理后一部分子问题(治3)
而且如果需要分治完后数据要求有序,那么就可以在分治的最后加入归并排序等手段。
何时使用cdq分治:①如果一个问题的解决需要去循环判断,且这样的问题有很多, 那么就看看能不能分治,减少计算量,从小减小复杂度。
转载于:https://www.cnblogs.com/justPassBy/p/5181415.html
hdu5618 (三维偏序,cdq分治)相关推荐
- 三维偏序/cdq分治/
三维偏序---cdq分治 cdq分治概述 二维偏序概述 二维偏序例题分析 三维偏序概述 例题分析 cdq分治概述 前置知识:(如果不懂要先去了解分治) > 分治: > 分而治之,将原问题不 ...
- BZOJ 2244 [SDOI2011]拦截导弹 (三维偏序CDQ+线段树)
题目大意: 洛谷传送门 不愧为SDOI的duliu题 第一问?二元组的最长不上升子序列长度?裸的三维偏序问题,直接上$CDQ$ 由于是不上升,需要查询某一范围的最大值,并不是前缀最大值,建议用线段树实 ...
- BZOJ3262/Luogu3810 陌上花开 (三维偏序,CDQ)
一个下午的光阴之死,凶手是细节与手残. 致命的一枪:BIT存权值时: for(; x <= maxx; x += x&-x) t[x] += w;//for(; x <= n; x ...
- [偏序关系与CDQ分治]【学习笔记】
组合数学真是太棒了 $CDQ$真是太棒了(雾 参考资料: 1.<组合数学> 2.论文 课件 很容易查到 3.sro __stdcall 偏序关系 关系: 集合$X$上的关系是$X$与$X$ ...
- CDQ分治 + 树状数组 ---- C. Goodbye Souvenir(三维偏序+思维)
题目链接 题目大意: 给定长度为nnn的数组, 定义数字XXX在[l,r][l,r][l,r]内的值为数字XXX在[l,r][l,r][l,r]内最后一次出现位置的下标减去第一次出现位置的下标 给定m ...
- HDU - 5517 Triple(三维偏序-二维树状数组/CDQ分治)
题目链接:点击查看 题目大意:给出 n 个二元对 ( a , b ) 和 m 个三元对 ( c , d , e ),对于所有 b == e 的二元对和三元对,可以通过某种运算形成一个新的三元对 ( a ...
- 洛谷 - P3810 【模板】三维偏序(陌上花开)(CDQ分治套树状数组)
题目链接:点击查看 题目大意:给出 n 个点,每个点有三个属性 a , b , c ,对于每个点 i 来说,求出有多少个 j 满足 a[ j ] <= a[ i ] && b[ ...
- 【原创】从BZOJ2683 简单题中 整 CDQ分治解决三维偏序
CDQ分治 题目描述 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子 ...
- 分治算法,逆序对,三维偏序与CDQ分治
分治算法基本思想 当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出. 对于这类问题,我们往往先把它分解成几个子问题,找到求出 ...
最新文章
- 第一个OpenGL程序
- 加密货币与智能合约的隐私 (二): 混音器和ring签名
- 小型校园网络拓扑RS配置
- c语言数据结构系统化,C语言数据结构+数据库+操作系统
- 如何让html标签不转义
- cocos2d-x内存自动释放机制
- Spark 1.0.0版本号公布
- Atitit dsl实现(1)------异常的库模式实现 异常的ast结构
- Android JS 通过X5WebView相互调用详解
- cppcheck下载及使用
- Windows安全基础-AD域
- 【人工智能】人工智能发展简史 | 复习笔记
- 【教学类-17-02】20221125《世界杯七巧板A4整页-随机参考图七巧板 3份一页》(大班)
- 2021-11-02 没羞没臊的商家装傻充愣昧着良知昧着基本人格耍赖达到丧心病狂程度.
- 爬取听书网有声小说音频数据
- yourls短链接项目部署及API使用
- knife4j或Swagger接口文档中找不到部分API文档
- 2021年了产品还是没有曝光?巨象跨境指纹浏览器教你2021年SNS营销不再落后
- 2-9 彩虹瓶 (20 分)
- python 生成字母图片
热门文章
- python ui自动_pytest+python下的UI自动化基础框架
- 计算机网络—SR选择重传协议
- Program Library HOWTO(2)
- 二进制转换为三进制 ——C++实现
- poj1700快速渡河问题(贪心策略,详细解析)
- 牛客小白月赛8: I. 路灯孤影(区间DP)
- 安卓使用Audio Record自定义录音
- 安卓网络连接全解:包括网络连接状态的监听、网络数据使用状态的监听、获取当前网络连接情况、启动wifi、获取当前连接wifi的网络情况、扫描wifi热点
- AD批量修改电阻封装记得按CTRL+A
- springboot接口返回封装与异常控制