CDQ解决一些三维偏序的问题
本来几天前就该记录的东西,硬生生被我拖到了现在,太懒了。。。
在cdq学习时,二维偏序已经解决了,无非就是先sort使第一维有序,然后再用cdq或者数据结构处理第二维。而三维偏序的时候呢,大佬的做法好像有树套树之类的,但是我不会,所以我选择cdq。
大体的思路很简单,首先也是先使第一维有序,然后cdq把第二维由小到大合并,这时再套个线段树或者树状数组处理第三维。来几题做一下
BZOJ1935园丁的烦恼
题目大意:一个花园里有n棵数,然后有m次询问,每次询问一个矩形里有多少颗树。
把原有的树视为更新操作,然后每个查询分为加上(0,0)到(x1-1,y1-1)范围内的树,减去(0,0)到(x1-1,y2)范围内的树,减去(0,0)到(x2,y1-1)范围内的树,加上(0,0)到(x2,y2)范围内的树,这样就可以处理一个二维前缀和,然后用cdq分治理套树状数组处理y轴
1 #include<cstdio> 2 #include<algorithm> 3 #define lowb(x) (x&(-x)) 4 using namespace std; 5 const int N=500118,M=500118,Y=10000118,Q=(M<<2)+N;//每个查询分4个 6 struct Nop{ 7 int x,y,op,w,id; 8 friend bool operator < (const Nop &n1,const Nop &n2){ 9 return n1.x==n2.x ? n1.op<n2.op : n1.x<n2.x; 10 } 11 }P[Q],temp[Q]; 12 int pn,maxy,ans[M<<1],sumy[Y]={0}; 13 void addp(int x,int y,int op,int w,int id){ 14 P[pn++]=(Nop){x,y,op,w,id}; 15 } 16 void updata(int y) 17 { 18 while(y<=maxy) 19 { 20 sumy[y]++; 21 y+=lowb(y); 22 } 23 } 24 int getsum(int y) 25 { 26 int sum=0; 27 while(y) 28 { 29 sum+=sumy[y]; 30 y-=lowb(y); 31 } 32 return sum; 33 } 34 void clear(int y) 35 { 36 while(y<=maxy) 37 { 38 if(sumy[y]) 39 sumy[y]=0; 40 else 41 break; 42 y+=lowb(y); 43 } 44 } 45 void cdq(int l,int r) 46 { 47 if(l==r) 48 return ; 49 int m=(l+r)>>1; 50 cdq(l,m); 51 cdq(m+1,r); 52 int i=l,j=m+1,k=l; 53 while(i<=m&&j<=r) 54 { 55 if(P[i]<P[j]) 56 { 57 if(P[i].op==0) 58 updata(P[i].y); 59 temp[k++]=P[i++]; 60 } 61 else 62 { 63 if(P[j].op==1) 64 ans[P[j].id]+=P[j].w*getsum(P[j].y); 65 temp[k++]=P[j++]; 66 } 67 } 68 while(i<=m) 69 temp[k++]=P[i++]; 70 while(j<=r) 71 { 72 if(P[j].op==1) 73 ans[P[j].id]+=P[j].w*getsum(P[j].y); 74 temp[k++]=P[j++]; 75 } 76 for(i=l;i<=r;i++) 77 { 78 clear(P[i].y); 79 P[i]=temp[i]; 80 } 81 } 82 int main() 83 { 84 int n,m,x1,y1,x2,y2; 85 while(~scanf("%d%d",&n,&m)) 86 { 87 pn=maxy=0; 88 for(int i=0;i<n;i++) 89 { 90 scanf("%d%d",&x1,&y1); 91 x1++,y1++; 92 addp(x1,y1,0,0,0); 93 maxy=max(maxy,y1); 94 } 95 for(int i=0;i<m;i++) 96 { 97 ans[i]=0; 98 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 99 x1++,y1++,x2++,y2++; 100 //拆分成四个查询 101 addp(x1-1,y1-1,1,1,i); 102 addp(x1-1,y2,1,-1,i); 103 addp(x2,y1-1,1,-1,i); 104 addp(x2,y2,1,1,i); 105 maxy=max(maxy,max(y1,y2)); 106 } 107 cdq(0,pn-1); 108 for(int i=0;i<m;i++) 109 printf("%d\n",ans[i]); 110 } 111 return 0; 112 }
园丁你为何烦恼呢
当然,这题很明显是个二维偏序问题,因为树本身都存在了,没有什么更新操作,直接离线树状数组处理就行。
1 #include<cstdio> 2 #include<algorithm> 3 #define lowb(x) (x&(-x)) 4 using namespace std; 5 const int N=500118,M=500118,Y=10000118,Q=(M<<2)+N; 6 struct Nop{ 7 int x,y,op,w,id; 8 friend bool operator < (const Nop &n1,const Nop &n2){ 9 return n1.x==n2.x ? n1.op<n2.op : n1.x<n2.x; 10 } 11 }P[Q]; 12 int pn,maxy,ans[M<<1],sumy[Y]={0}; 13 void addp(int x,int y,int op,int w,int id){ 14 P[pn++]=(Nop){x,y,op,w,id}; 15 } 16 void updata(int y) 17 { 18 while(y<=maxy) 19 { 20 sumy[y]++; 21 y+=lowb(y); 22 } 23 } 24 int getsum(int y) 25 { 26 int sum=0; 27 while(y) 28 { 29 sum+=sumy[y]; 30 y-=lowb(y); 31 } 32 return sum; 33 } 34 void clear(int y) 35 { 36 while(y<=maxy) 37 { 38 if(sumy[y]) 39 sumy[y]=0; 40 else 41 break; 42 y+=lowb(y); 43 } 44 } 45 int main() 46 { 47 int n,m,x1,y1,x2,y2; 48 while(~scanf("%d%d",&n,&m)) 49 { 50 pn=maxy=0; 51 for(int i=0;i<n;i++) 52 { 53 scanf("%d%d",&x1,&y1); 54 x1++,y1++; 55 addp(x1,y1,0,0,0); 56 maxy=max(maxy,y1); 57 } 58 for(int i=0;i<m;i++) 59 { 60 ans[i]=0; 61 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 62 x1++,y1++,x2++,y2++; 63 addp(x1-1,y1-1,1,1,i); 64 addp(x1-1,y2,1,-1,i); 65 addp(x2,y1-1,1,-1,i); 66 addp(x2,y2,1,1,i); 67 maxy=max(maxy,max(y1,y2)); 68 } 69 for(int i=1;i<=maxy;i++) 70 clear(i); 71 sort(P,P+pn); 72 for(int i=0;i<pn;i++) 73 { 74 if(!P[i].op) 75 updata(P[i].y); 76 else 77 ans[P[i].id]+=P[i].w*getsum(P[i].y); 78 } 79 for(int i=0;i<m;i++) 80 printf("%d\n",ans[i]); 81 } 82 return 0; 83 }
园丁不烦恼了
BZOJ1176Mokia
题目大意:维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.
S值并没有实际作用忽略就好。这题就不行像上面那题单纯的离线然后树状数组维护就行了,因为是有着一个更新的存在,不同的查询前面的更新是不一样的。所以就是我们大体的思路,把每个操作视为(操作时间,x轴,y轴)这样的带有附加消息的三维有序对,这样第一维已经有序了,我们就只需要把x轴cdq分治处理,然后y轴有树状数组处理,查询也就是维护个二维的前缀和。
1 #include<cstdio> 2 #include<algorithm> 3 #define lowb(x) (x&(-x)) 4 using namespace std; 5 const int N=160118,M=10118,Y=2001108,Q=(M<<2)+N; 6 struct Nop{ 7 int x,y,op,w,id; 8 friend bool operator < (const Nop &n1,const Nop &n2){ 9 return n1.x==n2.x ? n1.op<n2.op : n1.x<n2.x; 10 } 11 }P[Q],temp[Q]; 12 int pn,qn,maxy,ans[M]={0},sum[Y]={0}; 13 void addp(int x,int y,int op,int w,int id){ 14 P[pn++]=(Nop){x,y,op,w,id}; 15 } 16 void updata(int y,int val) 17 { 18 while(y<=maxy) 19 { 20 sum[y]+=val; 21 y+=lowb(y); 22 } 23 } 24 int getsum(int y) 25 { 26 int ans=0; 27 while(y) 28 { 29 ans+=sum[y]; 30 y-=lowb(y); 31 } 32 return ans; 33 } 34 void clear(int y) 35 { 36 while(y<=maxy) 37 { 38 if(sum[y]) 39 sum[y]=0; 40 else 41 break; 42 y+=lowb(y); 43 } 44 } 45 void cdq(int l,int r) 46 { 47 if(l==r) 48 return ; 49 int m=(l+r)>>1; 50 cdq(l,m); 51 cdq(m+1,r); 52 int i=l,j=m+1,k=l; 53 while(i<=m&&j<=r) 54 { 55 if(P[i]<P[j]) 56 { 57 if(P[i].op==1) 58 updata(P[i].y,P[i].w); 59 temp[k++]=P[i++]; 60 } 61 else 62 { 63 if(P[j].op==2) 64 ans[P[j].id]+=P[j].w*getsum(P[j].y); 65 temp[k++]=P[j++]; 66 } 67 } 68 while(i<=m) 69 temp[k++]=P[i++]; 70 while(j<=r) 71 { 72 if(P[j].op==2) 73 ans[P[j].id]+=P[j].w*getsum(P[j].y); 74 temp[k++]=P[j++]; 75 } 76 for(i=l;i<=r;i++) 77 { 78 clear(P[i].y); 79 P[i]=temp[i]; 80 } 81 } 82 int main() 83 { 84 int n,op,x1,y1,x2,y2,a; 85 while(~scanf("%d%d",&n,&n)) 86 { 87 pn=qn=maxy=0; 88 while(scanf("%d",&op)&&op!=3) 89 { 90 if(op==1) 91 { 92 scanf("%d%d%d",&x1,&y1,&a); 93 x1++,y1++; 94 addp(x1,y1,op,a,0); 95 maxy=max(maxy,y1); 96 } 97 else 98 { 99 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 100 x1++,y1++,x2++,y2++; 101 addp(x1-1,y1-1,op,1,qn); 102 addp(x1-1,y2,op,-1,qn); 103 addp(x2,y1-1,op,-1,qn); 104 addp(x2,y2,op,1,qn); 105 qn++; 106 maxy=max(maxy,max(y1,y2)); 107 } 108 } 109 cdq(0,pn-1); 110 for(int i=0;i<qn;i++) 111 { 112 printf("%d\n",ans[i]); 113 ans[i]=0; 114 } 115 } 116 return 0; 117 }
园丁都会了这个肯定会了
BZOJ3262陌上花开
题目大意:有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),用三个整数表示。现在要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽,当且仅Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
这就是个三维偏序的问题了,没有什么更新和查询就是(s,c,m)的三维有序对求顺序对,我们同样是让sort按s由小到大,s相同按c排,c相同按m排的cmp使得第一维s有序,然后cdq分治处理第二维c,树状数组维护第三维m,最后提交,好的,wrong了。因为一个重要的点,,两朵花可能有同样的属性,如果我们不去重的话,那么相同的属性的话,因为它们的顺序不同造成它们的等级不同。所以我们把属性相同的归为一类,然后统计这一类有多少个,然后作为树状数组维护的权值维护就行,有个小细节就是当分到最小的子区间也就是只有一朵花时,它的等级应该还得提升它的权值-1,因为那些和它属性相同的合为一类了,具体的就看代码注释。
1 #include<cstdio> 2 #include<algorithm> 3 #define lowb(x) (x&(-x)) 4 using namespace std; 5 const int N=100118,K=200118; 6 struct Flower{ 7 int id,s,c,m,w; 8 friend bool operator == (const Flower &f1,const Flower &f2){ 9 return f1.s==f2.s&&f1.m==f2.m&&f1.c==f2.c; 10 } 11 }F[N],temp[N]; 12 int fn,ans[N]={0},rank[N]={0},summ[K]={0}; 13 //ans[i]保存编号为i的花的等级,也就是属性小于或等于它的数目 14 bool cmp(const Flower &f1,const Flower &f2){ 15 return f1.s==f2.s ? (f1.c==f2.c ? f1.m<f2.m : f1.c<f2.c) : f1.s<f2.s; 16 } 17 void updata(int m,int val) 18 { 19 while(m<=200000) 20 { 21 summ[m]+=val; 22 m+=lowb(m); 23 } 24 } 25 int getsum(int m) 26 { 27 int ans=0; 28 while(m) 29 { 30 ans+=summ[m]; 31 m-=lowb(m); 32 } 33 return ans; 34 } 35 void clear(int m) 36 { 37 while(m<=200000) 38 { 39 if(summ[m]) 40 summ[m]=0; 41 else 42 break; 43 m+=lowb(m); 44 } 45 } 46 void cdq(int l,int r) 47 { 48 if(l==r) 49 { 50 ans[F[l].id]+=F[l].w-1;//因为相同属性的归到一类了 51 //所以还得加上F[l].w-1,也就是除它之外, 52 //其他相同属性的花的数目 53 return ; 54 } 55 int mid=(l+r)>>1; 56 cdq(l,mid); 57 cdq(mid+1,r); 58 int i=l,j=mid+1,k=l; 59 while(i<=mid&&j<=r) 60 { 61 if(F[i].c<=F[j].c) 62 { 63 updata(F[i].m,F[i].w); 64 temp[k++]=F[i++]; 65 } 66 else 67 { 68 ans[F[j].id]+=getsum(F[j].m); 69 temp[k++]=F[j++]; 70 } 71 } 72 while(i<=mid) 73 temp[k++]=F[i++]; 74 while(j<=r) 75 { 76 ans[F[j].id]+=getsum(F[j].m); 77 temp[k++]=F[j++]; 78 } 79 for(i=l;i<=r;i++) 80 { 81 clear(F[i].m); 82 F[i]=temp[i]; 83 } 84 } 85 int main() 86 { 87 int n,k; 88 while(~scanf("%d%d",&n,&k)) 89 { 90 for(int i=0;i<n;i++) 91 { 92 F[i].w=1; 93 scanf("%d%d%d",&F[i].s,&F[i].c,&F[i].m); 94 } 95 sort(F,F+n,cmp); 96 fn=0; 97 //去重 98 for(int i=0;i<n;i++) 99 { 100 if(i&&F[i]==F[i-1])//如果和前一朵花属性相同,归到一类 101 F[fn-1].w++; 102 else 103 { 104 F[fn]=F[i]; 105 F[fn].id=fn++; 106 } 107 } 108 //原先n朵花去重就只有fn朵 109 cdq(0,fn-1); 110 for(int i=0;i<fn;i++) 111 { 112 rank[ans[F[i].id]]+=F[i].w; 113 ans[F[i].id]=0; 114 } 115 for(int i=0;i<n;i++) 116 { 117 printf("%d\n",rank[i]); 118 rank[i]=0; 119 } 120 } 121 return 0; 122 }
公子世无双
转载于:https://www.cnblogs.com/LMCC1108/p/10737124.html
CDQ解决一些三维偏序的问题相关推荐
- 三维偏序/cdq分治/
三维偏序---cdq分治 cdq分治概述 二维偏序概述 二维偏序例题分析 三维偏序概述 例题分析 cdq分治概述 前置知识:(如果不懂要先去了解分治) > 分治: > 分而治之,将原问题不 ...
- CodeForces - 160E Buses and People(线段树+三维偏序)
题目链接:点击查看 题目大意:(网上复制一下别人的题意..懒) 有n辆公交车,每辆公交车有s(起始点),f(终点),t(发车时间) (行驶不需要时间) 有m个人,每个人有l(起点),r(终点),t(出 ...
- P4390 [BOI2007]Mokia 摩基亚 (CDQ解决三维偏序问题)
题目描述 摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统.和其他的定位系统一样,它能够迅速回答任何形如"用户C的位置在哪?"的问题,精确到毫米.但其真正高科 ...
- P3157 [CQOI2011]动态逆序对 (CDQ解决三维偏序问题)
P3157 [CQOI2011]动态逆序对 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任 ...
- 【原创】从BZOJ2683 简单题中 整 CDQ分治解决三维偏序
CDQ分治 题目描述 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子 ...
- HDU - 5517 Triple(三维偏序-二维树状数组/CDQ分治)
题目链接:点击查看 题目大意:给出 n 个二元对 ( a , b ) 和 m 个三元对 ( c , d , e ),对于所有 b == e 的二元对和三元对,可以通过某种运算形成一个新的三元对 ( a ...
- 分治算法,逆序对,三维偏序与CDQ分治
分治算法基本思想 当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出. 对于这类问题,我们往往先把它分解成几个子问题,找到求出 ...
- CDQ分治 + 树状数组 ---- C. Goodbye Souvenir(三维偏序+思维)
题目链接 题目大意: 给定长度为nnn的数组, 定义数字XXX在[l,r][l,r][l,r]内的值为数字XXX在[l,r][l,r][l,r]内最后一次出现位置的下标减去第一次出现位置的下标 给定m ...
- 洛谷 - P3810 【模板】三维偏序(陌上花开)(CDQ分治套树状数组)
题目链接:点击查看 题目大意:给出 n 个点,每个点有三个属性 a , b , c ,对于每个点 i 来说,求出有多少个 j 满足 a[ j ] <= a[ i ] && b[ ...
最新文章
- 从设计原则谈软件开发(二)
- 2017.11.7 Python 制作EFM32/ AVR批量烧录工具
- Python利用matplotlib.animation和matplotlib.pyplot和ffmpeg录制动画并保存为MP4文件
- 【Pytorch神经网络理论篇】 11 卷积网络模型+Sobel算子原理
- java设置默认参数_关于java:如何设置默认方法参数值?
- mysql jdbc实例_jdbc操作mysql数据库实例
- ggbiplot设置分组_比PCA更好用的监督排序—LDA分析、作图及添加置信-ggord
- Web服务器Nginx多方位优化策略
- ActiveMQ Stomp的重新投递和死信
- Win10企业版安装应用商店
- 【流体力学】从无量纲化的NS方程看几个准则数:施特劳哈尔数、雷诺数、弗劳德数
- Mac OS读写NTFS
- 万能码不可能中创造可能(安全扫码专业委员会)
- 爬虫之requests
- 选择香港虚拟主机需要注意的,如何选购优质的虚拟主机
- 云南农业大学matlab,云南农业大学关于公第七届学生科技.doc
- google mapView 用法
- macOS Catalina 10.15.7正式版 CDR/ISO镜像 for VMware
- matlab的GUI设计
- 离散数学 | 集合论、二元关系、集合的基数
热门文章
- com.android.pngp.tln,Android资源之图像资源(图像级别资源)
- 你可能没听过的 Java 8 中的 10 个特性
- xtrabackup备份mysql_xtrabackup备份mysql
- 总结新浪friendship接口
- linux的O的字体让我满意那些
- PyQt5学习--基本窗口控件--QMainWindow
- 【转载】什么时候该选C语言实现业务逻辑,什么时候该选Python?
- 前端模板技术的全面总结
- ArcGIS API for JavaScript——绘制工具(Draw)
- SpringBoot开发流程