CDQ分治笔记

以前一直不会CDQ……然后经常听到dalao们说“这题直接CDQ啊”“CDQ不就秒了吗”的时候我只能瑟瑟发抖QAQ

CDQ分治

其实CDQ分治就是二分分治,每次将$[l,r]$的问题划分为$[l,mid]$和$[mid+1,r]$的子问题来解决,裸的时间复杂度是$O(nlogn)$。但是cdq的特殊要求是区间左半边的操作不会影响右半边的操作,一般适用于多次询问以及需要维护多个维度关键值的问题。(其实这种题也可以写树套树&KD树,dalao们又把我碾在了地上QAQ)

注意:cdq经常要在中间给数组排序,要使用归并来保证复杂度,直接sort的话或多一个$log$(Orzhjw)

三维偏序问题

三维偏序的著名不用我说了吧。。。几乎是所有人cdq的入门题,会cdq的人应该都写过吧。。。

先从一维偏序问题开始考虑,这就是一个经典的逆序对问题,用树状数组解决;

二维偏序的话可以对第一维排序,保证这一维有序后再对第二维建树状数组维护;

问题变成了三维,排序+树状数组也只能解决两维,还有一维就要用cdq分治(树套树)来搞:

注意到第一维排序后前一半的答案不会影响后一半的答案,于是把两边的区间分别按照第二维排序,然后建个树状数组解决;

(yrx:树套树好写易懂好调肯定写树套树啊)

代码:(BZOJ3262陌上花开 模板题)

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #define lb(x) (x&(-x))
 7 using namespace std;
 8 struct task{
 9     int a,b,c,tot,ans;
10     task(){
11         tot=0;
12     }
13 }q[100001],s[100001];
14 int n,m,tot=0,ans[100001],t[500001];
15 bool cmp(task a,task b){
16     if(a.a!=b.a)return a.a<b.a;
17     if(a.b!=b.b)return a.b<b.b;
18     if(a.c!=b.c)return a.c<b.c;
19     return false;
20 }
21 bool _cmp(task a,task b){
22     if(a.b!=b.b)return a.b<b.b;
23     if(a.c!=b.c)return a.c<b.c;
24     if(a.a!=b.a)return a.a<b.a;
25     return false;
26 }
27 void add(int x,int v){
28     for(;x<=m;x+=lb(x)){
29         t[x]+=v;
30     }
31 }
32 int sum(int x){
33     int ret=0;
34     for(;x;x-=lb(x)){
35         ret+=t[x];
36     }
37     return ret;
38 }
39 void cdq(int l,int r){
40     if(l==r){
41         s[l].ans+=s[l].tot-1;
42         return;
43     }
44     int mid=(l+r)/2;
45     cdq(l,mid);
46     cdq(mid+1,r);
47     sort(s+l,s+mid+1,_cmp);
48     sort(s+mid+1,s+r+1,_cmp);
49     int j=l;
50     for(int i=mid+1;i<=r;i++){
51         while(j<=mid&&s[j].b<=s[i].b)add(s[j].c,s[j].tot),j++;
52         s[i].ans+=sum(s[i].c);
53     }
54     for(int i=l;i<j;i++)add(s[i].c,-s[i].tot);
55 }
56 int main(){
57     scanf("%d%d",&n,&m);
58     for(int i=1;i<=n;i++){
59         scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].c);
60         q[i].ans=1;
61     }
62     sort(q+1,q+n+1,cmp);
63     for(int i=1;i<=n;i++){
64         if(i!=1&&q[i].a==q[i-1].a&&q[i].b==q[i-1].b&&q[i].c==q[i-1].c)s[tot].tot++;
65         else s[++tot]=q[i],s[tot].tot=1;
66     }
67     cdq(1,tot);
68     sort(s+1,s+tot+1,cmp);
69     for(int i=1;i<=tot;i++)ans[s[i].ans]+=s[i].tot;
70     for(int i=1;i<=n;i++)printf("%d
",ans[i]);
71     return 0;
72 }

(这个代码多了一个log跑的巨慢无比)

一些刷题记录:

【BZOJ2176】天使玩偶

KD树大法好

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #define inf 1000000000
  7 using namespace std;
  8 struct node{
  9     int d[2],mi[2],mx[2],ls,rs;
 10 }t[2000001];
 11 int D,n,m,rt,x,y,op,tot=0,ans;
 12 bool cmp(node a,node b){
 13     return a.d[D]!=b.d[D]?a.d[D]<b.d[D]:a.d[D^1]<b.d[D^1];
 14 }
 15 void pushup(int u){
 16     int l=t[u].ls,r=t[u].rs;
 17     if(l){
 18         t[u].mi[0]=min(t[u].mi[0],t[l].mi[0]);
 19         t[u].mi[1]=min(t[u].mi[1],t[l].mi[1]);
 20         t[u].mx[0]=max(t[u].mx[0],t[l].mx[0]);
 21         t[u].mx[1]=max(t[u].mx[1],t[l].mx[1]);
 22     }
 23     if(r){
 24         t[u].mi[0]=min(t[u].mi[0],t[r].mi[0]);
 25         t[u].mi[1]=min(t[u].mi[1],t[r].mi[1]);
 26         t[u].mx[0]=max(t[u].mx[0],t[r].mx[0]);
 27         t[u].mx[1]=max(t[u].mx[1],t[r].mx[1]);
 28     }
 29 }
 30 void build(int &u,int l,int r,int d){
 31     D=d;
 32     int mid=(l+r)/2;
 33     u=mid;
 34     nth_element(t+l,t+u+1,t+r+1,cmp);
 35     t[u].mi[0]=t[u].mx[0]=t[u].d[0];
 36     t[u].mi[1]=t[u].mx[1]=t[u].d[1];
 37     if(u>l)build(t[u].ls,l,mid-1,D^1);
 38     if(u<r)build(t[u].rs,mid+1,r,D^1);
 39     pushup(u);
 40 }
 41 void ins(int k){
 42     int d=0,now=rt;
 43     for(;;){
 44         t[now].mi[0]=min(t[now].mi[0],t[k].mi[0]);
 45         t[now].mi[1]=min(t[now].mi[1],t[k].mi[1]);
 46         t[now].mx[0]=max(t[now].mx[0],t[k].mx[0]);
 47         t[now].mx[1]=max(t[now].mx[1],t[k].mx[1]);
 48         if(t[k].d[d]>=t[now].d[d]){
 49             if(!t[now].rs){
 50                 t[now].rs=k;
 51                 return;
 52             }
 53             now=t[now].rs;
 54         }else{
 55             if(!t[now].ls){
 56                 t[now].ls=k;
 57                 return;
 58             }
 59             now=t[now].ls;
 60         }
 61         d^=1;
 62     }
 63 }
 64 int dis(int u,int x,int y){
 65      int ret=0;
 66      if(x<t[u].mi[0])ret+=t[u].mi[0]-x;
 67      if(x>t[u].mx[0])ret+=x-t[u].mx[0];
 68      if(y<t[u].mi[1])ret+=t[u].mi[1]-y;
 69      if(y>t[u].mx[1])ret+=y-t[u].mx[1];
 70      return ret;
 71 }
 72 int query(int u,int x,int y){
 73     int l,r,now;
 74     now=abs(t[u].d[0]-x)+abs(t[u].d[1]-y);
 75     ans=min(ans,now);
 76     if(t[u].ls)l=dis(t[u].ls,x,y);
 77     else l=inf;
 78     if(t[u].rs)r=dis(t[u].rs,x,y);
 79     else r=inf;
 80     if(l<r){
 81         if(l<ans)query(t[u].ls,x,y);
 82         if(r<ans)query(t[u].rs,x,y);
 83     }else{
 84         if(r<ans)query(t[u].rs,x,y);
 85         if(l<ans)query(t[u].ls,x,y);
 86     }
 87 }
 88 int main(){
 89     scanf("%d%d",&n,&m);
 90     for(int i=1;i<=n;i++){
 91         scanf("%d%d",&t[i].d[0],&t[i].d[1]);
 92     }
 93     build(rt,1,n,0);
 94     tot=n;
 95     for(int i=1;i<=m;i++){
 96         scanf("%d%d%d",&op,&x,&y);
 97         if(op==1){
 98             ++tot;  
 99             t[tot].mi[0]=t[tot].mx[0]=t[tot].d[0]=x;
100             t[tot].mi[1]=t[tot].mx[1]=t[tot].d[1]=y;
101             ins(tot);
102         }else{
103             ans=inf;
104             query(rt,x,y);
105             printf("%d
",ans);
106         }
107     }
108     return 0;
109 }

【BZOJ1176】Mokia

下面一题的加强版,必须要写cdq

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #define lb(x) (x&(-x))
 7 using namespace std;
 8 struct node{
 9     int v,x,y,op,d,id;
10 }q[500001],tmp[500001];
11 int s,w,x,y,a,b,k,op,cnt=0,tot=0,aans[500001],ans[500001],t[5000001];
12 bool cmp(node a,node b){
13     if(a.x!=b.x)return a.x<b.x;
14     if(a.y!=b.y)return a.y<b.y;
15     return a.op<b.op;
16 }
17 void add(int u,int x){
18     for(;u<=w;u+=lb(u)){
19         t[u]+=x;
20     }
21 }
22 int query(int u){
23     int ret=0;
24     for(;u;u-=lb(u)){
25         ret+=t[u];
26     }
27     return ret;
28 }
29 void cdq(int l,int r){
30     if(l==r)return;
31     int mid=(l+r)/2,L=l,R=mid+1;
32     for(int i=l;i<=r;i++){
33         if(q[i].v<=mid&&!q[i].op)add(q[i].y,q[i].d);
34         if(q[i].v>mid&&q[i].op)ans[q[i].id]+=query(q[i].y)*q[i].d;
35     }
36     for(int i=l;i<=r;i++){
37         if(q[i].v<=mid&&!q[i].op)add(q[i].y,-q[i].d);
38     }
39     for(int i=l;i<=r;i++){
40         if(q[i].v<=mid)tmp[L++]=q[i];
41         else tmp[R++]=q[i];
42     }
43     for(int i=l;i<=r;i++)q[i]=tmp[i];
44     cdq(l,mid);
45     cdq(mid+1,r);
46 }
47 int main(){
48     scanf("%d%d",&s,&w);
49     for(;;){
50         scanf("%d",&op);
51         if(op==1){
52             scanf("%d%d%d",&x,&y,&k);
53             q[++cnt]=(node){cnt,x,y,0,k,0};
54         }else if(op==2){
55             scanf("%d%d%d%d",&x,&y,&a,&b);
56             tot++;
57             aans[tot]=s*(a-x+1)*(b-y+1);
58             q[++cnt]=(node){cnt,a,b,1,1,tot};
59             q[++cnt]=(node){cnt,a,y-1,1,-1,tot};
60             q[++cnt]=(node){cnt,x-1,b,1,-1,tot};
61             q[++cnt]=(node){cnt,x-1,y-1,1,1,tot};
62         }else break;
63     }
64     sort(q+1,q+cnt+1,cmp);
65     cdq(1,cnt);
66     for(int i=1;i<=tot;i++)printf("%d
",ans[i]+aans[i]);
67     return 0;
68 }

【BZOJ2683】简单题

KD树大法好(成功跑到垫底QAQ

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 using namespace std;
  7 int D;
  8 struct kdnode{
  9     int ls,rs,num,v,d[2],mi[2],mx[2];
 10     int &operator [](int x){
 11         return d[x];
 12     }
 13     friend bool operator <(kdnode a,kdnode b){
 14         return a[D]<b[D];
 15     }
 16 }t[200001],rb[200001],s;
 17 int n,op,x1,yy,x2,y2,v,rt=0,tot=0,R=5000,ans=0;
 18 bool inside(int x1,int yy,int x2,int y2,int x3,int y3,int x4,int y4){
 19     return x1<=x3&&x2>=x4&&yy<=y3&&y2>=y4;
 20 }
 21 bool outside(int x1,int yy,int x2,int y2,int x3,int y3,int x4,int y4){
 22     return x1>x4||x2<x3||yy>y4||y2<y3;
 23 }
 24 void pushup(int u){
 25     int l=t[u].ls,r=t[u].rs;
 26     for(int i=0;i<=1;i++){
 27         t[u].mi[i]=t[u].mx[i]=t[u][i];
 28         if(l)t[u].mi[i]=min(t[u].mi[i],t[l].mi[i]);
 29         if(l)t[u].mx[i]=max(t[u].mx[i],t[l].mx[i]);
 30         if(r)t[u].mi[i]=min(t[u].mi[i],t[r].mi[i]);
 31         if(r)t[u].mx[i]=max(t[u].mx[i],t[r].mx[i]);
 32     }
 33     t[u].num=t[l].num+t[r].num+t[u].v;
 34 }
 35 int query(int u,int x1,int yy,int x2,int y2){
 36     int ret=0;
 37     if(!u)return 0;
 38     if(inside(x1,yy,x2,y2,t[u].mi[0],t[u].mi[1],t[u].mx[0],t[u].mx[1]))return t[u].num;
 39     if(outside(x1,yy,x2,y2,t[u].mi[0],t[u].mi[1],t[u].mx[0],t[u].mx[1]))return 0;
 40     if(inside(x1,yy,x2,y2,t[u][0],t[u][1],t[u][0],t[u][1]))ret+=t[u].v;
 41     ret+=query(t[u].ls,x1,yy,x2,y2)+query(t[u].rs,x1,yy,x2,y2);
 42     return ret;
 43 }
 44 void ins(int &u,bool d){
 45     if(!u){
 46         u=++tot;
 47         t[u][0]=t[u].mi[0]=t[u].mx[0]=s[0];
 48         t[u][1]=t[u].mi[1]=t[u].mx[1]=s[1];
 49     }
 50     if(s[0]==t[u][0]&&s[1]==t[u][1]){
 51         t[u].v+=s.v;
 52         t[u].num+=s.v;
 53         return; 
 54     }
 55     if(s[d]<t[u][d])ins(t[u].ls,d^1);
 56     else ins(t[u].rs,d^1);
 57     pushup(u);
 58 }
 59 int rebuild(int l,int r,bool d){
 60     if(l>r)return 0;
 61     int mid=(l+r)/2;
 62     D=d;
 63     nth_element(rb+l,rb+mid,rb+r+1);
 64     t[mid]=rb[mid];
 65     t[mid].ls=rebuild(l,mid-1,d^1);
 66     t[mid].rs=rebuild(mid+1,r,d^1);
 67     pushup(mid);
 68     return mid;
 69 }
 70 int main(){
 71     scanf("%d",&n);
 72     for(;;){
 73         scanf("%d",&op);
 74         if(op==1){
 75             scanf("%d%d%d",&x1,&yy,&v);
 76             //x1^=ans;
 77             //yy^=ans;
 78             //v^=ans;
 79             s[0]=x1;
 80             s[1]=yy;
 81             s.num=s.v=v;
 82             ins(rt,0);
 83             //printf("aa %d
",tot); 
 84             if(tot==R){
 85                 //printf("zjtywwakioi
");
 86                 for(int j=1;j<=tot;j++){
 87                     rb[j]=t[j];
 88                 }
 89                 rt=rebuild(1,tot,0);
 90                 R+=5000;
 91             }
 92         }else if(op==2){
 93             scanf("%d%d%d%d",&x1,&yy,&x2,&y2);
 94             //x1^=ans;
 95             //yy^=ans;
 96             //x2^=ans;
 97             //y2^=ans;
 98             printf("%d
",(ans=query(rt,x1,yy,x2,y2)));
 99         }else break;
100     }
101     return 0;
102 }

【BZOJ1492】【NOI2007】Cash

CDQ分治维护凸包+斜率优化DP

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #define eps 1e-7
 7 #define inf 1e15
 8 using namespace std;
 9 struct task{
10     double x,y,a,b,k,r;
11     int v,id;
12 }q[100001],tmp[100001];
13 double gtk(int a,int b){
14     if(!b)return -inf;
15     if(fabs(q[a].x-q[b].x)<eps)return inf;
16     return (q[a].y-q[b].y)/(q[a].x-q[b].x);
17 }
18 int n,top,s[100001];
19 double f[100001];
20 bool cmp(task a,task b){
21     return a.k>b.k;
22 }
23 void cdq(int l,int r){
24     if(l==r){
25         f[l]=max(f[l],f[l-1]);
26         q[l].y=f[l]/(q[l].a*q[l].r+q[l].b);
27         q[l].x=q[l].r*q[l].y;
28         return;
29     }
30     int mid=(l+r)/2,L=l,R=mid+1,j=1;
31     for(int i=l;i<=r;i++){
32         if(q[i].id<=mid)tmp[L++]=q[i];
33         else tmp[R++]=q[i];
34     }
35     for(int i=l;i<=r;i++)q[i]=tmp[i];
36     cdq(l,mid);
37     top=0;
38     for(int i=l;i<=mid;i++){
39         while(top>1&&gtk(s[top-1],s[top])<gtk(s[top-1],i)+eps)top--;
40         s[++top]=i;
41     }
42     s[++top]=0;
43     for(int i=mid+1;i<=r;i++){
44         while(j<top&&gtk(s[j],s[j+1])+eps>q[i].k)j++;
45         f[q[i].id]=max(f[q[i].id],q[s[j]].x*q[i].a+q[s[j]].y*q[i].b);
46     }
47     cdq(mid+1,r);
48     L=l,R=mid+1;
49     for(int i=l;i<=r;i++){
50         if(((q[L].x<q[R].x||(fabs(q[L].x-q[R].x)<eps&&q[L].y<q[R].y))||R>r)&&L<=mid)tmp[i]=q[L++];
51         else tmp[i]=q[R++];
52     }
53     for(int i=l;i<=r;i++)q[i]=tmp[i];
54 }
55 int main(){
56     scanf("%d%lf",&n,&f[0]);
57     for(int i=1;i<=n;i++){
58         scanf("%lf%lf%lf",&q[i].a,&q[i].b,&q[i].r);
59         q[i].k=-q[i].a/q[i].b;
60         q[i].id=i;
61     }
62     sort(q+1,q+n+1,cmp);
63     cdq(1,n);
64     printf("%.2lf",f[n]);
65     return 0;
66 }

【HDU5126】stars

毒瘤题,四维CDQ or 三维KD树,先咕

原文地址:https://www.cnblogs.com/dcdcbigbig/p/9488544.html