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

  在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=,M=,Y=,Q=(M<<)+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<<],sumy[Y]={};
  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=;
  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]=;
  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)>>;
  50. cdq(l,m);
  51. cdq(m+,r);
  52. int i=l,j=m+,k=l;
  53. while(i<=m&&j<=r)
  54. {
  55. if(P[i]<P[j])
  56. {
  57. if(P[i].op==)
  58. updata(P[i].y);
  59. temp[k++]=P[i++];
  60. }
  61. else
  62. {
  63. if(P[j].op==)
  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==)
  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=;
  88. for(int i=;i<n;i++)
  89. {
  90. scanf("%d%d",&x1,&y1);
  91. x1++,y1++;
  92. addp(x1,y1,,,);
  93. maxy=max(maxy,y1);
  94. }
  95. for(int i=;i<m;i++)
  96. {
  97. ans[i]=;
  98. scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
  99. x1++,y1++,x2++,y2++;
  100. //拆分成四个查询
  101. addp(x1-,y1-,,,i);
  102. addp(x1-,y2,,-,i);
  103. addp(x2,y1-,,-,i);
  104. addp(x2,y2,,,i);
  105. maxy=max(maxy,max(y1,y2));
  106. }
  107. cdq(,pn-);
  108. for(int i=;i<m;i++)
  109. printf("%d\n",ans[i]);
  110. }
  111. return ;
  112. }

园丁你为何烦恼呢

  当然,这题很明显是个二维偏序问题,因为树本身都存在了,没有什么更新操作,直接离线树状数组处理就行。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #define lowb(x) (x&(-x))
  4. using namespace std;
  5. const int N=,M=,Y=,Q=(M<<)+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<<],sumy[Y]={};
  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=;
  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]=;
  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=;
  51. for(int i=;i<n;i++)
  52. {
  53. scanf("%d%d",&x1,&y1);
  54. x1++,y1++;
  55. addp(x1,y1,,,);
  56. maxy=max(maxy,y1);
  57. }
  58. for(int i=;i<m;i++)
  59. {
  60. ans[i]=;
  61. scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
  62. x1++,y1++,x2++,y2++;
  63. addp(x1-,y1-,,,i);
  64. addp(x1-,y2,,-,i);
  65. addp(x2,y1-,,-,i);
  66. addp(x2,y2,,,i);
  67. maxy=max(maxy,max(y1,y2));
  68. }
  69. for(int i=;i<=maxy;i++)
  70. clear(i);
  71. sort(P,P+pn);
  72. for(int i=;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=;i<m;i++)
  80. printf("%d\n",ans[i]);
  81. }
  82. return ;
  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=,M=,Y=,Q=(M<<)+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]={},sum[Y]={};
  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=;
  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]=;
  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)>>;
  50. cdq(l,m);
  51. cdq(m+,r);
  52. int i=l,j=m+,k=l;
  53. while(i<=m&&j<=r)
  54. {
  55. if(P[i]<P[j])
  56. {
  57. if(P[i].op==)
  58. updata(P[i].y,P[i].w);
  59. temp[k++]=P[i++];
  60. }
  61. else
  62. {
  63. if(P[j].op==)
  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==)
  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=;
  88. while(scanf("%d",&op)&&op!=)
  89. {
  90. if(op==)
  91. {
  92. scanf("%d%d%d",&x1,&y1,&a);
  93. x1++,y1++;
  94. addp(x1,y1,op,a,);
  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-,y1-,op,,qn);
  102. addp(x1-,y2,op,-,qn);
  103. addp(x2,y1-,op,-,qn);
  104. addp(x2,y2,op,,qn);
  105. qn++;
  106. maxy=max(maxy,max(y1,y2));
  107. }
  108. }
  109. cdq(,pn-);
  110. for(int i=;i<qn;i++)
  111. {
  112. printf("%d\n",ans[i]);
  113. ans[i]=;
  114. }
  115. }
  116. return ;
  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=,K=;
  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]={},rank[N]={},summ[K]={};
  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<=)
  20. {
  21. summ[m]+=val;
  22. m+=lowb(m);
  23. }
  24. }
  25. int getsum(int m)
  26. {
  27. int ans=;
  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<=)
  38. {
  39. if(summ[m])
  40. summ[m]=;
  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-;//因为相同属性的归到一类了
  51. //所以还得加上F[l].w-1,也就是除它之外,
  52. //其他相同属性的花的数目
  53. return ;
  54. }
  55. int mid=(l+r)>>;
  56. cdq(l,mid);
  57. cdq(mid+,r);
  58. int i=l,j=mid+,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=;i<n;i++)
  91. {
  92. F[i].w=;
  93. scanf("%d%d%d",&F[i].s,&F[i].c,&F[i].m);
  94. }
  95. sort(F,F+n,cmp);
  96. fn=;
  97. //去重
  98. for(int i=;i<n;i++)
  99. {
  100. if(i&&F[i]==F[i-])//如果和前一朵花属性相同,归到一类
  101. F[fn-].w++;
  102. else
  103. {
  104. F[fn]=F[i];
  105. F[fn].id=fn++;
  106. }
  107. }
  108. //原先n朵花去重就只有fn朵
  109. cdq(,fn-);
  110. for(int i=;i<fn;i++)
  111. {
  112. rank[ans[F[i].id]]+=F[i].w;
  113. ans[F[i].id]=;
  114. }
  115. for(int i=;i<n;i++)
  116. {
  117. printf("%d\n",rank[i]);
  118. rank[i]=;
  119. }
  120. }
  121. return ;
  122. }

公子世无双

CDQ解决一些三维偏序的问题的更多相关文章

  1. 并不对劲的cdq分治解三维偏序

    为了反驳隔壁很对劲的太刀流,并不对劲的片手流决定与之针锋相对,先一步发表cdq分治解三维偏序. 很对劲的太刀流在这里->  参照一.二维偏序的方法,会发现一位偏序就是直接排序,可以看成通过排序使 ...

  2. 【算法学习】【洛谷】cdq分治 & P3810 三维偏序

    cdq是何许人也?请参看这篇:https://wenku.baidu.com/view/3b913556fd0a79563d1e7245.html. 在这篇论文中,cdq提出了对修改/询问型问题(Mo ...

  3. hdu5618(cdq分治求三维偏序)

    题意:给n(n<=100000)个点,坐标为(xi,yi,zi)(1<=xi,yi,zi<=100000),定义一个点A比一个点B小,当且仅当xA<=xB,yA<=yB, ...

  4. BZOJ 3262: 陌上花开 (cdq分治,三维偏序)

    #include <iostream> #include <stdio.h> #include <algorithm> using namespace std; c ...

  5. SPOJ:Another Longest Increasing Subsequence Problem(CDQ分治求三维偏序)

    Given a sequence of N pairs of integers, find the length of the longest increasing subsequence of it ...

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

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

  7. HDU 5517 【二维树状数组///三维偏序问题】

    题目链接:[http://acm.split.hdu.edu.cn/showproblem.php?pid=5517] 题意:定义multi_set A<a , d>,B<c , d ...

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

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

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

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

随机推荐

  1. ccpc湘潭邀请赛 Partial Sum

    选定最多m的区间,使区间和的绝对值最大.但是左右端点不能重复选取 首先涉及到区间和的问题,就应该想到用前缀和去优化 这里对前缀和排序 然后贪心的去选取最大.次大 (比赛的时候脑子堵的很,没想出来 可惜 ...

  2. 3.Shell的基本功能

    3.Shell的基本功能Bash是Bourne-Again Shell的缩写.Bourne Shell的内部命令在Bash中同样适用.3.1 Shell语法3.1.1 Shell操作shell读取和执 ...

  3. Tomcat 的部署器

    要使用一个Web应用程序,必须要将表示该应用程序的Context实例部署到一个Host实例中,在Tomcat中,Context实例可以用WAR文件的形式来部署,也可以将整个WEB应用程序复制到Tomc ...

  4. ES6入门五:箭头函数、函数与ES6新语法

    箭头函数的基本用法与特点 函数与ES6新语法 一.箭头函数的基本用法与特点 声明箭头函数采用声明变量和常量的关键字:var.let.const 箭头函数的参数:没有参数用"()"空 ...

  5. HTML5之历史记录(实现的当页面应用路由器的底层)

    history hashchange与popstate 一.history history.back():加载history列表中的前一个URL history.forward():加载history ...

  6. java技术面试之面试题大全

    转载自:http://blog.csdn.net/lijizhi19950123/article/details/77679489 Java 面试知识点总结 本篇文章会对面试中常遇到的Java技术点进 ...

  7. ceres for Android 太慢的解决方法

    跨平台编译了ceres,结果在android平台上运行的太慢,优化一次要0.3秒左右,时不时要一两秒.这太扯了.没辙了,在google上瞎搜索,看到 Jacobian evaluation is ve ...

  8. Spring Boot WebFlux整合mongoDB

    引入maven文件 <dependency> <groupId>org.springframework.boot</groupId> <artifactId& ...

  9. Linux CentOS 7 防火墙与端口设置操作

    CentOS升级到7之后用firewall代替了iptables来设置Linux端口, 下面是具体的设置方法: []:选填 <>:必填 [<zone>]:作用域(block.d ...

  10. Asp.Net Zero通用打印实现

    Asp.Net Zero是一款非常优秀的web框架,可以用来快速构建业务系统.框架满足了业务系统所需的大部分通用功能,但是系统必须的打印报表功能一直没有实现.下面给大家介绍如何在zero中集成打印功能 ...