CDQ分治

CDQ分治相较于普通分治,多了左区间处理后对于右区间的影响。

利用这一点,CDQ分治可以用来做很多数据结构的题目(树状数组、线段树),加一个log的时间复杂度来优化一维。

操作:

假设有两维,那么我们先按第一维排序,然后对于每次分治,排序第二维,这样遍历下来就是两维都排序好的了。

如果有三维,在前两位都有序的基础上,遍历是用树状数组插入,这样就可以实现三维有序了。

注意:

什么时候CDQ(l,mid) CDQ(mid+1,r) 再处理CDQ(l,r)?这里是因为左区间对右区间的影响对右区间的分治没有影响。如果有,需要CDQ(l,mid)再处理CDQ(l,r)再CDQ(mid+1,r)。

   \\\;


   \\\;

二维:最长递增子序列的数量 51nod 1376

题意: n(5e4)的数组,有多少个LIS(最长递增子序列)。

解析:

在CDQ左区间后,我们需要做的是统计左区间对于右区间的影响。

因为需要递增,所以我们对L~R中的数从小到大遍历

  1. 对于num,当它在左区间的时候,说明接下来的在右边的数都可以从它转移(因为已按数值从小到大排序),我们维护一个tmp,表示左区间上的最长LIS的长度
  2. 当在右区间的时候,左区间对它的影响为:如果当前的tmp比它本身的更优,则从tmp转移(因为tmp所代表的位置在左区间,且数值较小)。

转移:

左边已有Len,Many,那么更新到右边就是Len+1,Many。如果更优则直接取代,如果Len相同则加上Many(前面的LIS连上右边的点)。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pill;
#define mk make_pair
const int mod = 1e9+7;
int a[50009];
pill ans[50009];//pos {Len Many}:到pos位置的|LIS|=Len,有Many个int rk[50009];
bool cmp(int x,int y){if(a[x]!=a[y])return a[x]<a[y];return x>y;//对于相同的数,因为严格递增,所以不能转移,故将右区间的排在前面
}void MAX(pill &x,pill y){if(x.first<y.first)x=y;else if(x.first==y.first){x.second+=y.second;if(x.second>mod)x.second-=mod;}
}void out(int n){for(int i=1;i<=n;i++)printf("%d : (%d %d)\n",i,ans[i].first,ans[i].second);
}void CDQ(int l,int r){if(l==r)return;int mid=l+r>>1;CDQ(l,mid);for(int i=l;i<=r;i++)rk[i]=i;sort(rk+l,rk+r+1,cmp);pill tmp=mk(0,0);for(int i=l;i<=r;i++){int id=rk[i];if(id<=mid){//左区间MAX(tmp,ans[id]);}else{MAX(ans[id],mk(tmp.first+1,tmp.second));}}CDQ(mid+1,r);
}int main(){int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++)ans[i]={1,1};CDQ(1,n);//out(n);pill Ans=mk(0,0);for(int i=1;i<=n;i++)MAX(Ans,ans[i]);printf("%d\n",Ans.second);return 0;
}

&ThickSpace; \\\;


&ThickSpace; \\\;

三维:陌上花开 BZOJ 3262

题意: 每朵花有三个属性值,花x超过花y当且仅当x的三个属性值都大于等于y的对应的三个属性值,设一朵花超过的花的数量为v,求v=0,1…n-1的花各有多少。

解析:

也就是求三维偏序:对a排序,b用CDQ分治实现,c用树状数组维护。

CDQ(L,mid)CDQ(mid+1,R)后,我们需要计算左区间对右区间的影响,即:对于在右区间的x,除了右区间中比x小的,还要加上左区间的。

按b排序好[L,mid]和[mid+1,R],用类似归并的思想一一得出右区间的每一个位置,左区间中有多少个比它少。

具体操作就是:将所有b小于x的花,他们的c值插到对应的树状数组,再找小于等于x的c值的个数。这些就是满足a(第一次排序)、满足b(选的都是b小于等于x的b值的点)、满足c(树状数组)的所有左区间中的花。

#include<bits/stdc++.h>
using namespace std;
#define debug(i) printf("#%d\n",i)
const int N = 2e5+5;
struct node{int a,b,c,ct;int v;bool operator < (const node &r)const{if(a!=r.a)return a<r.a;if(b!=r.b)return b<r.b;return c<r.c;}bool operator == (const node &r)const{return a==r.a&&b==r.b&&c==r.c;}bool operator != (const node &r)const{return a!=r.a||b!=r.b||c!=r.c;}
}e[N>>1];int n,k;
int tr[N];//c值作为下标
void add(int pos,int v){for(int i=pos;i<=k;i+=i&-i){tr[i]+=v;}
}
int query(int pos){int ans=0;while(pos>0){ans+=tr[pos];pos-=pos&-pos;}return ans;
}bool cmp_b(node x,node y){return x.b<y.b;
}
void CDQ(int l,int r){if(l==r)return;int mid=l+r>>1;CDQ(l,mid),CDQ(mid+1,r);sort(e+l,e+mid+1,cmp_b);sort(e+mid+1,e+r+1,cmp_b);int limit=l,up=mid+1;while(up<=r){while(limit<=mid&&e[limit].b<=e[up].b){add(e[limit].c,e[limit].ct);limit++;}e[up].v+=query(e[up].c);up++;}for(int i=l;i<limit;i++)add(e[i].c,-e[i].ct);//limit不算
}int ans[N];int main(){scanf("%d%d",&n,&k);for(int i=1;i<=n;i++){scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);e[i].ct=1;e[i].v=0;}//*******需要排除相同的,因为两个完全相同的最后之后算一次//*******假设为x,y,且x排在前面,则y不能影响到xsort(e+1,e+1+n);int size=0;e[0].a=-1;for(int i=1;i<=n;i++){if(e[i]!=e[i-1])e[++size]=e[i];else{e[size].ct++;e[size].v++;//自己超过自己}}CDQ(1,size);memset(ans,0,sizeof(int)*(1+n));for(int i=1;i<=size;i++){ans[e[i].v]+=e[i].ct;}for(int i=0;i<n;i++){printf("%d\n",ans[i]);}
}

&ThickSpace; \\\;


&ThickSpace; \\\;

四维:三维点对的中间的点的数量 HDU5126

题意:

解析:

求两个坐标之间的点(就是那个长方体),可以将这个空间用八个点代表的区间隔开(自行脑补)。

题目就变成了求对(A,B,C)有多少个(a,b,c)满足(a<=A…)。

首先因为时间有先后,所以第一次的排序就以时间为标准了。
CDQ处理第一维的排序,再用CDQ处理第二维的排序,当前两维有序后插树状数组使第三维有序即可。

注意: 数组开至少八倍。。。T了好久

#include<bits/stdc++.h>
using namespace std;
#define debug(x,i) printf("%s%d\n",x,i)const int N =1000005;struct node{int a,b,c;int id;int kind;node(){}node(int a,int b,int c,int kind,int id):a(a),b(b),c(c),id(id),kind(kind){}
}e[N],tmp1[N],tmp2[N];int size,size1,size2;
bool cmp_a(node x,node y){return x.a<y.a||x.a==y.a&&x.id<y.id;
}
bool cmp_b(node x,node y){return x.b<y.b||x.b==y.b&&x.id<y.id;//相同需要算入,则x.id<y.id
}int tr[N<<1];//离散化后的最大值
void add(int pos,int v,int n){while(pos<=n){tr[pos]+=v;pos+=pos&-pos;}
}
int query(int pos){int ans=0;while(pos){ans+=tr[pos];pos-=pos&-pos;}return ans;
}int ans[N];
int non[N],all;//离散化//********************************************************************void CDQ_b(int l,int r){//此时,右区间的a值一定大于左区间的a值,再按b排序if(l>=r)return;int mid=l+r>>1;CDQ_b(l,mid);CDQ_b(mid+1,r);size2=0;for(int i=l;i<=mid;i++)if(tmp1[i].kind==0)tmp2[++size2]=tmp1[i];for(int i=mid+1;i<=r;i++)if(tmp1[i].kind!=0)tmp2[++size2]=tmp1[i];sort(tmp2+1,tmp2+1+size2,cmp_b);for(int i=1;i<=size2;i++){if(tmp2[i].kind==0)add(tmp2[i].c,1,all);            //左边:插入  右边:维护答案else{ans[tmp2[i].id]+=query(tmp2[i].c)*tmp2[i].kind;//printf("count (%d,%d,%d)\n",tmp2[i].a,tmp2[i].b,tmp2[i].c);}}for(int i=1;i<=size2;i++){if(tmp2[i].kind==0)add(tmp2[i].c,-1,all);}
}void CDQ_a(int l,int r){//维护左区间对右区间的贡献,按a排序if(l>=r)return;int mid=l+r>>1;CDQ_a(l,mid);CDQ_a(mid+1,r);size1=0;for(int i=l;i<=mid;i++)if(e[i].kind==0)tmp1[++size1]=e[i];for(int i=mid+1;i<=r;i++)if(e[i].kind!=0)tmp1[++size1]=e[i];sort(tmp1+1,tmp1+1+size1,cmp_a);//kind就可以表示其为左区间还是右区间,所以可以省略idxCDQ_b(1,size1);
}int main(){int t;scanf("%d",&t);while(t--){size=0;all=0;int n;scanf("%d",&n);queue<int>out;for(int i=1;i<=n;i++){int k;scanf("%d",&k);if(k==1){int a,b,c;scanf("%d%d%d",&a,&b,&c);e[++size]=node(a,b,c,0,i);non[++all]=c;}else{out.push(i);int a1,b1,c1,a2,b2,c2;scanf("%d%d%d%d%d%d",&a1,&b1,&c1,&a2,&b2,&c2);a1--,b1--,c1--;//(a1,b1,c1)在计算的范围,所以减一e[++size]=node(a2,b2,c2,1,i);e[++size]=node(a1,b2,c2,-1,i);e[++size]=node(a2,b1,c2,-1,i);e[++size]=node(a2,b2,c1,-1,i);e[++size]=node(a1,b1,c2,1,i);e[++size]=node(a1,b2,c1,1,i);e[++size]=node(a2,b1,c1,1,i);e[++size]=node(a1,b1,c1,-1,i);non[++all]=c1;non[++all]=c2;ans[i]=0;}}sort(non+1,non+1+all);all=unique(non+1,non+1+all)-non-1;for(int i=1;i<=size;i++){//第三维离散化e[i].c=lower_bound(non+1,non+1+all,e[i].c)-non;}//已按时间排序CDQ_a(1,size);while(!out.empty()){int idx=out.front();out.pop();printf("%d\n",ans[idx]);}}
}

CDQ分治(二维CDQ 、三维CDQ+树状数组、四维CDQ+CDQ+树状数组)相关推荐

  1. Android 高级UI解密 (三) :Canvas裁剪 与 二维、三维Camera几何变换(图层Layer原理)

    Android的绘图机制是核心内容之一,无论是什么样的功能最终都是以图像的形式呈现给用户.因此掌握Android的绘图技巧,有助于Android理解层次的提高,在面对产品经理提出的idea时也更有底气 ...

  2. R语言plotly可视化:使用PCA算法进行数据降维、使用plotly可视化PCA所有的主成分绘制散点图矩阵、降维后的两个(三个)核心主成分的二维、三维可视化图形、方差解释的量、载荷图等

    R语言plotly可视化:使用PCA算法进行数据降维.使用plotly可视化PCA所有的主成分绘制散点图矩阵.降维后的两个(三个)核心主成分的二维.三维可视化图形.方差解释的量.载荷图等 目录

  3. linux c语言 malloc动态分配指针,C语言malloc函数为一维,二维,三维数组分配空间...

    c语言允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必在程序的声明部分定义,也不必等到函数结束时才释放,而是需要时随时开辟,不需要时随时释放,这些数据存储在堆区.可以根据需要,向系统申请 ...

  4. 从二维到三维,可见Web3D技术的重要性,让线上3D产品展示所见即所得

    原文地址:Web3D技术|从二维到三维,所见即所得 导读: 从2D到3D图像展示,从二维平面到三维立体,为我们实现了所见即所得.你是否想过有一天,我们能在网购时看到真实产品的每一个细节,仿佛产品就在你 ...

  5. 类的设计与实现1、设计一个图形抽象类Graph,该类中有成员变量图形类型(type),维度信息(dimension,二维或三维);成员方法计算面积(computeArea); 2、设计一个接口

    类的设计与实现 1.设计一个图形抽象类Graph,该类中有成员变量图形类型(type),维度信息(dimension,二维或三维):成员方法计算面积(computeArea); 2.设计一个接口IDi ...

  6. k-means聚类、以及二维、三维可视化

    说明 最近做聚类分析,记录一下聚类后,利用PCA将特征降维到二维.三维,进行聚类可视化的方法 数据处理和EDA部分就不放在这里了,有兴趣的可以点击下方链接看完整的项目,fork后可以看到完整代码,可下 ...

  7. N圆最密堆积、最小外接正方形的matlab求解(二维、三维等圆Packing 问题)

    圆形最密堆积.最小外接正方形的matlab求解(二维.三维等圆Packing 问题) 0 前言 1 N个圆的最小外接正方形求解 2 N个球的最小外接立方体求解 惯例声明:本人没有相关的工程应用经验,只 ...

  8. c语言malloc申请三维数组,C语言malloc函数为一维,二维,三维数组分配空间

    c语言允许建立内存动态分配区域,以存放一些临时用的数据,这些数据不必在程序的声明部分定义,也不必等到函数结束时才释放,而是需要时随时开辟,不需要时随时释放,这些数据存储在堆区.可以根据需要,向系统申请 ...

  9. matlab二维、三维矩阵转换、排序、转置等问题

    1.matlab二维转换为三维矩阵 这里用到reshape函数 格式为AA1=reshape(A1,[行,列,页]) 如下所示 A1=[2 2 2 2 2.5 2.5 2.5 2.5 1.8 1.8 ...

  10. 核密度估计(二维、三维)

    核密度估计是通过平滑的峰值函数来拟合样本数据,利用连续的密度曲线描述随机变量的分布形态,具有稳健性强.模型依赖性弱的特性.现在已经被广泛的应用到动态演进分析当中,核密度估计通常有二维.三维表现形式,如 ...

最新文章

  1. 使用Python中的卷积神经网络进行恶意软件检测
  2. 内核中的对象操作的方法模块 和 C++ 构造和析构的对比
  3. 拿到国际AI比赛冠军的,居然是个搞教育的
  4. Python-OpenCV 笔记1 -- 图像与视频的读取、显示、保存
  5. MicroPython 1.8.6重新支持512K的模块
  6. matlab 抽样判决代码,matlab抽样判决器
  7. 虚拟机启动时出现operating system not found如何解决?
  8. 成人教育考试报名照片的尺寸是多少?大一寸照片怎么做?
  9. 新华字典电子版_《新华字典》不收[王莹]字考证
  10. Unity快速搭建城市场景
  11. Kubernetes核心概念总结
  12. centos7 查看本地ip地址
  13. windows和linux系统云服务器桌面远程连接教程
  14. SRS SDP解析流程
  15. 从0到1玩转戴尔G7 7588 macOS Win 双系统
  16. uniapp 日期计算年龄
  17. 声音四要素:音强、音调、音色和波形包络
  18. Activiti7学习笔记、非常详细 | 进阶篇
  19. 到底什么才是真正的商业智能(BI)
  20. AMPL IDE语法整理

热门文章

  1. 我的数据可视化之旅:从天文学家到数据可视化专家养成记
  2. # 科研牛人告诉研究生怎么看文献,怎么写论文csdn
  3. android的一些简单配置修改(2)
  4. 如何查看win10专业版是否永久激活
  5. 刷题之路:DP思想(动态规划)
  6. c语言switch逻辑用语,第一章 第二节用逻辑用语.doc
  7. 如何使用 OpenTracing 和 Jaeger 追踪 Pulsar 消息
  8. 有时用weblogic用户启动weblogic时会报错的原因以及解决办法
  9. gensim bm25模型保存与加载
  10. 青蛙跳台阶c语言递归函数,【递归】青蛙跳台阶问题