给定空间中的n个点,问每个点有多少个点小于等于自己。

先来分析简单的二维的情况,那么只要将x坐标排序,那么这样的问题就可以划分为两个子问题,,这样的分治有一个特点,即前一个子问题的解决是独立的,而后一个子问题的解决依赖于前一个子问题,即用前一个子问题来解决后一个子问题,而不是合并。 这就是cdq分治。

具体的代码如下。

void cdq(int l, int r){
if(l==r) return;
int m = (l+r)>>;
cdq(l,m);
cdq(m+,r);
//按y进行排序,那么问题就变成两个y递增的集合,
//后一个集合中的每个y在前一个集合中有多少个y小于等于它
sort(a+l,a+m+,cmp);
sort(a+m+,a+r+,cmp);
int j = l;
for(int i=m+;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 = + ;
Point a[N];
class BIT{
public:
int sum[N];
int n;
void init(){
n = ;
memset(sum,,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= ;
while(x>){
ret += sum[x];
x -= lowbit(x);
}
return ret;
}
}bit; void cdq(int l, int r){
if(l==r)return;
int m = (l+r)>>;
cdq(l,m);
cdq(m+,r);
sort(a+l,a+m+,cmp);
sort(a+m+,a+r+,cmp);
int j = l;
for(int i=m+;i<=r;++i){
for(;j<=m &&a[j].y<=a[i].y;++j)
bit.modify(a[j].z,);
a[i].sum += bit.getSum(a[i].z);
}
for(int i=l; i<j; ++i)
bit.modify(a[i].z,-); } int ans[N];
int main(){
int t,n;
scanf("%d",&t);
while(t--){ scanf("%d",&n);
for(int i=;i<n;++i){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].id = i; a[i].sum=;}
sort(a,a+n);
bit.init();
cdq(,n-);
sort(a,a+n);
for(int i=;i<n;){
int j = i + ;
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=;i<n;++i)
printf("%d\n",ans[i]);
}
return ;
}

第二份代码,在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 = + ;
Point a[N];
class BIT{
public:
int sum[N];
int n;
void init(){
n = ;
memset(sum,,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= ;
while(x>){
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)>>;
cdq(l,m);
cdq(m+,r);
//sort(a+l,a+m+1,cmp);
//sort(a+m+1,a+r+1,cmp);
int j = l;
for(int i=m+;i<=r;++i){
for(;j<=m &&a[j].y<=a[i].y;++j)
bit.modify(a[j].z,);
a[i].sum += bit.getSum(a[i].z);
}
for(int i=l; i<j; ++i)
bit.modify(a[i].z,-); //归并排序, 这样就不需要上面的sort了
int i = l ;
j = m+;
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=;i<n;++i){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].id = i; a[i].sum=;}
sort(a,a+n);
bit.init();
cdq(,n-);
sort(a,a+n);
for(int i=;i<n;){
int j = i + ;
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=;i<n;++i)
printf("%d\n",ans[i]);
}
return ;
}

具体算法流程如下:

1.将整个操作序列分为两个长度相等的部分(分)

2.递归处理前一部分的子问题(治1)

3.计算前一部分的子问题中的修改操作对后一部分子问题的影响(治2)

4.递归处理后一部分子问题(治3)

而且如果需要分治完后数据要求有序,那么就可以在分治的最后加入归并排序等手段。

何时使用cdq分治:①如果一个问题的解决需要去循环判断,且这样的问题有很多, 那么就看看能不能分治,减少计算量,从小减小复杂度。

hdu5618 (三维偏序,cdq分治)的更多相关文章

  1. Luogu 3810 & BZOJ 3262 陌上花开/三维偏序 | CDQ分治

    Luogu 3810 & BZOJ 3263 陌上花开/三维偏序 | CDQ分治 题面 \(n\)个元素,每个元素有三个值:\(a_i\), \(b_i\) 和 \(c_i\).定义一个元素的 ...

  2. bzoj3262: 陌上花开 三维偏序cdq分治

    三维偏序裸题,cdq分治时,左侧的x一定比右侧x小,然后分别按y排序,对于左侧元素按y大小把z依次插入到树状数组里,其中维护每个左侧元素对右侧元素的贡献,在bit查询即可 /************* ...

  3. [bzoj] 3263 陌上花开 洛谷 P3810 三维偏序|| CDQ分治 && CDQ分治讲解

    原题 定义一个点比另一个点大为当且仅当这个点的三个值分别大于等于另一个点的三个值.每比一个点大就为加一等级,求每个等级的点的数量. 显然的三维偏序问题,CDQ的板子题. CDQ分治: CDQ分治是一种 ...

  4. BZOJ3262 陌上花开 —— 三维偏序 CDQ分治

    题目链接:https://vjudge.net/problem/HYSBZ-3262 3262: 陌上花开 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit ...

  5. BZOJ 3295:[Cqoi2011]动态逆序对(三维偏序 CDQ分治+树状数组)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3295 题意:简单明了. 思路:终于好像有点明白CDQ分治处理三维偏序了.把删除操作看作是插入操作,那 ...

  6. 三维偏序[cdq分治学习笔记]

    三维偏序 就是让第一维有序 然后归并+树状数组求两维 cdq+cdq不会 告辞 #include <bits/stdc++.h> // #define int long long #def ...

  7. 洛谷P3810-陌上开花(三维偏序, CDQ, 树状数组)

    链接: https://www.luogu.org/problem/P3810#submit 题意: 一个元素三个属性, x, y, z, 给定求f(b) = {ax <= bx, ay < ...

  8. COGS 2479. [HZOI 2016]偏序 [CDQ分治套CDQ分治 四维偏序]

    传送门 给定一个有n个元素的序列,元素编号为1~n,每个元素有三个属性a,b,c,求序列中满足i<j且ai<aj且bi<bj且ci<cj的数对(i,j)的个数. 对于100%的 ...

  9. BZOJ 2716/2648 SJY摆棋子 (三维偏序CDQ+树状数组)

    题目大意: 洛谷传送门 这明明是一道KD-Tree,CDQ分治是TLE的做法 化简式子,$|x1-x2|-|y1-y2|=(x1+y1)-(x2+y2)$ 而$CDQ$分治只能解决$x1 \leq x ...

随机推荐

  1. 一些窗口API函数,比如SetForegroundWindow,SwitchToThisWindow

    SetForegroundWindowSwitchToThisWindow procedure TApplication.BringToFront;varTopWindow: HWnd;beginif ...

  2. 部署Spring Boot应用

    在开发Spring Boot应用的过程中,Spring Boot直接执行public static void main()函数并启动一个内嵌的应用服务器(取决于类路径上的以来是Tomcat还是jett ...

  3. 14.1.1 InnoDB as the Default MySQL Storage Engine

    14.1 Introduction to InnoDB 14.1.1 InnoDB as the Default MySQL Storage Engine 14.1.2 Checking InnoDB ...

  4. gcc中__attribute__ ((constructor(101)))做成.a库成功链接

    1.cpp:------------------------------------------------ #include int test() __attribute__ ((construct ...

  5. hdu1427之速算24点

    速算24点 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  6. Swift - 各种手势检测大全(UIGestureRecognizer及其子类)

    UIGestureRecognizer有许多子类,用于监听一些常见的手势事件,这些子类主要有: 1,UISwipeGestureRecognizer:滑动(快速移动) 1 2 3 4 5 6 7 8 ...

  7. jTDS驱动兼容性问题

    Java连接SQL Server 2000数据库时,有两种方法: (1)通过Microsoft的JDBC驱动连接.此JDBC驱动共有三个文件,分别是mssqlserver.jar.msutil.jar ...

  8. flex网上办(苹果)桌面系统仿真

    1.有登录界面 2.能够载入app(每一个app是单独的swf),并可拖动app的图标互相叠加 3.桌面上显示的哪些APP与目录是依据登陆的用户信息.从webservice中读取的(名字.图标信息等) ...

  9. eclipse package,source folder,folder差别及相互转换

    在eclipse下, package, source folder, folder都是目录.   它们的差别例如以下:   package:当你在建立一个package时,它自己主动建立到source ...

  10. 移动App測试实战:顶级互联网企业软件測试和质量提升最佳实践

    这篇是计算机类的优质预售推荐>>>><移动App測试实战:顶级互联网企业软件測试和质量提升最佳实践> 国内顶级互联网公司測试实战经验总结.阿里.腾讯.京东.携程.百 ...