zoukankan      html  css  js  c++  java
  • 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树,先咕

  • 相关阅读:
    Python之路【第七十一篇】:django日更
    Python之路【第七十篇】:django日更
    Python之路【第六十九篇】:django日更
    选包
    Python之路【第六十八篇】:django日更
    Python之路【第六十七篇】:django日更
    Python之路【第六十六篇】:django日更
    Python之路【第六十五篇】:django日更
    Python之路【第六十四篇】:django日更
    Python之路【第六十三篇】:django日更
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9488544.html
Copyright © 2011-2022 走看看