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\n",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\n",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\n",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\n",tot); 
 84             if(tot==R){  85                 //printf("zjtywwakioi\n");
 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\n",(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树,先咕

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM