本来几天前就该记录的东西,硬生生被我拖到了现在,太懒了。。。

  在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解决一些三维偏序的问题相关推荐

  1. 三维偏序/cdq分治/

    三维偏序---cdq分治 cdq分治概述 二维偏序概述 二维偏序例题分析 三维偏序概述 例题分析 cdq分治概述 前置知识:(如果不懂要先去了解分治) > 分治: > 分而治之,将原问题不 ...

  2. CodeForces - 160E Buses and People(线段树+三维偏序)

    题目链接:点击查看 题目大意:(网上复制一下别人的题意..懒) 有n辆公交车,每辆公交车有s(起始点),f(终点),t(发车时间) (行驶不需要时间) 有m个人,每个人有l(起点),r(终点),t(出 ...

  3. P4390 [BOI2007]Mokia 摩基亚 (CDQ解决三维偏序问题)

    题目描述 摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统.和其他的定位系统一样,它能够迅速回答任何形如"用户C的位置在哪?"的问题,精确到毫米.但其真正高科 ...

  4. P3157 [CQOI2011]动态逆序对 (CDQ解决三维偏序问题)

    P3157 [CQOI2011]动态逆序对 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任 ...

  5. 【原创】从BZOJ2683 简单题中 整 CDQ分治解决三维偏序

    CDQ分治 题目描述 你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作: 命令 参数限制 内容 1 x y A 1<=x,y<=N,A是正整数 将格子 ...

  6. HDU - 5517 Triple(三维偏序-二维树状数组/CDQ分治)

    题目链接:点击查看 题目大意:给出 n 个二元对 ( a , b ) 和 m 个三元对 ( c , d , e ),对于所有 b == e 的二元对和三元对,可以通过某种运算形成一个新的三元对 ( a ...

  7. 分治算法,逆序对,三维偏序与CDQ分治

    分治算法基本思想 当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出. 对于这类问题,我们往往先把它分解成几个子问题,找到求出 ...

  8. CDQ分治 + 树状数组 ---- C. Goodbye Souvenir(三维偏序+思维)

    题目链接 题目大意: 给定长度为nnn的数组, 定义数字XXX在[l,r][l,r][l,r]内的值为数字XXX在[l,r][l,r][l,r]内最后一次出现位置的下标减去第一次出现位置的下标 给定m ...

  9. 洛谷 - P3810 【模板】三维偏序(陌上花开)(CDQ分治套树状数组)

    题目链接:点击查看 题目大意:给出 n 个点,每个点有三个属性 a , b , c ,对于每个点 i 来说,求出有多少个 j 满足 a[ j ] <= a[ i ] && b[ ...

最新文章

  1. 从设计原则谈软件开发(二)
  2. 2017.11.7 Python 制作EFM32/ AVR批量烧录工具
  3. Python利用matplotlib.animation和matplotlib.pyplot和ffmpeg录制动画并保存为MP4文件
  4. 【Pytorch神经网络理论篇】 11 卷积网络模型+Sobel算子原理
  5. java设置默认参数_关于java:如何设置默认方法参数值?
  6. mysql jdbc实例_jdbc操作mysql数据库实例
  7. ggbiplot设置分组_比PCA更好用的监督排序—LDA分析、作图及添加置信-ggord
  8. Web服务器Nginx多方位优化策略
  9. ActiveMQ Stomp的重新投递和死信
  10. Win10企业版安装应用商店
  11. 【流体力学】从无量纲化的NS方程看几个准则数:施特劳哈尔数、雷诺数、弗劳德数
  12. Mac OS读写NTFS
  13. 万能码不可能中创造可能(安全扫码专业委员会)
  14. 爬虫之requests
  15. 选择香港虚拟主机需要注意的,如何选购优质的虚拟主机
  16. 云南农业大学matlab,云南农业大学关于公第七届学生科技.doc
  17. google mapView 用法
  18. macOS Catalina 10.15.7正式版 CDR/ISO镜像 for VMware
  19. matlab的GUI设计
  20. 离散数学 | 集合论、二元关系、集合的基数

热门文章

  1. com.android.pngp.tln,Android资源之图像资源(图像级别资源)
  2. 你可能没听过的 Java 8 中的 10 个特性
  3. xtrabackup备份mysql_xtrabackup备份mysql
  4. 总结新浪friendship接口
  5. linux的O的字体让我满意那些
  6. PyQt5学习--基本窗口控件--QMainWindow
  7. 【转载】什么时候该选C语言实现业务逻辑,什么时候该选Python?
  8. 前端模板技术的全面总结
  9. ArcGIS API for JavaScript——绘制工具(Draw)
  10. SpringBoot开发流程