zoukankan      html  css  js  c++  java
  • HDU

    题目链接

    题目大意:一共有Q(1<=Q<=50000)组操作,操作分为两种:

    1.在x,y,z处添加一颗星星

    2.询问以(x1,y1,z1)与(x2,y2,z2)为左上和右下顶点的矩形之间的星星数

    所有坐标取值范围均为[1,1e9]

    思路:由于坐标取值范围太大(即使离散化后也很大),3维的数组肯定开不下,所以只能另辟蹊径。

    解法一(两重CDQ+树状数组,需将z坐标离散化):

    1)将每个查询操作拆分为8个(容斥),将所有操作放入一个数组qr中

    2)将所有操作按时间排序(其实不用,因为读入的顺序就是按时间排好的)

    3)第一次分治:将qr中每个子区间按x坐标从小到大排序,将左区间元素与右区间查询放入qr2中

    4)第二次分治(嵌套在第一次分治中):将qr2中每个子区间按y坐标从小到大排序,统计左区间元素对右区间查询的贡献(利用树状数组记录z值)

    注意每次分治结束后,需将左右区间的所有元素按相应坐标大小归并排好序。另外离散化的时候注意下标要从1开始而不是从0开始,否则树状数组可能会陷入死循环(在这个地方T了n次...QAQ)

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 const int N=5e5+10;
     5 struct QR {
     6     int f,x,y,z,i;
     7 } qr[N],qr2[N],qr3[N];
     8 int c[N],n,ans[N],nq,tot,zz[N],maxz;
     9 int lowbit(int x) {return x&-x;}
    10 void add(int u,int x) {
    11     for(; u<=maxz; u+=lowbit(u))c[u]+=x;
    12 }
    13 int get(int u) {
    14     int ret=0;
    15     for(; u; u-=lowbit(u))ret+=c[u];
    16     return ret;
    17 }
    18 
    19 void cdq2(int l,int r) {
    20     if(l==r)return;
    21     int mid=(l+r)>>1;
    22     cdq2(l,mid),cdq2(mid+1,r);
    23     int L=l,R=mid+1;
    24     for(; R<=r; ++R)if(qr2[R].f) {
    25             for(; L<=mid&&qr2[L].y<=qr2[R].y; ++L)if(!qr2[L].f)add(qr2[L].z,1);
    26             ans[qr2[R].i]+=get(qr2[R].z)*qr2[R].f;
    27         }
    28     for(int i=l; i<L; ++i)if(!qr2[i].f)add(qr2[i].z,-1);
    29     L=l,R=mid+1;
    30     for(int i=l; i<=r; ++i) {
    31         if(R>r||(L<=mid&&qr2[L].y<=qr2[R].y))qr3[i]=qr2[L++];
    32         else qr3[i]=qr2[R++];
    33     }
    34     for(int i=l; i<=r; ++i)qr2[i]=qr3[i];
    35 }
    36 
    37 void cdq1(int l,int r) {
    38     if(l==r)return;
    39     int mid=(l+r)>>1;
    40     cdq1(l,mid),cdq1(mid+1,r);
    41     int L=l,R=mid+1,m=0;
    42     for(; R<=r; ++R)if(qr[R].f) {
    43             for(; L<=mid&&qr[L].x<=qr[R].x; ++L)if(!qr[L].f)qr2[m++]=qr[L];
    44             qr2[m++]=qr[R];
    45         }
    46     if(m>0)cdq2(0,m-1);
    47     L=l,R=mid+1;
    48     for(int i=l; i<=r; ++i) {
    49         if(R>r||(L<=mid&&qr[L].x<qr[R].x))qr2[i]=qr[L++];
    50         else qr2[i]=qr[R++];
    51     }
    52     for(int i=l; i<=r; ++i)qr[i]=qr2[i];
    53 }
    54 
    55 int main() {
    56     int T;
    57     scanf("%d",&T);
    58     while(T--) {
    59         nq=tot=0;
    60         memset(c,0,sizeof c);
    61         memset(ans,0,sizeof ans);
    62         scanf("%d",&n);
    63         for(int i=0; i<n; ++i) {
    64             int f;
    65             scanf("%d",&f);
    66             if(f==1) {
    67                 int x,y,z;
    68                 scanf("%d%d%d",&x,&y,&z);
    69                 qr[nq++]= {0,x,y,z,0};
    70             } else {
    71                 int x1,y1,z1,x2,y2,z2;
    72                 scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
    73                 qr[nq++]= {1,x2,y2,z2,tot};
    74                 qr[nq++]= {-1,x1-1,y2,z2,tot};
    75                 qr[nq++]= {-1,x2,y1-1,z2,tot};
    76                 qr[nq++]= {-1,x2,y2,z1-1,tot};
    77                 qr[nq++]= {1,x1-1,y1-1,z2,tot};
    78                 qr[nq++]= {1,x2,y1-1,z1-1,tot};
    79                 qr[nq++]= {1,x1-1,y2,z1-1,tot};
    80                 qr[nq++]= {-1,x1-1,y1-1,z1-1,tot++};
    81             }
    82         }
    83         maxz=0;
    84         for(int i=0; i<nq; ++i)zz[maxz++]=qr[i].z;
    85         sort(zz,zz+maxz);
    86         maxz=unique(zz,zz+maxz)-zz;
    87         for(int i=0; i<nq; ++i)qr[i].z=lower_bound(zz,zz+maxz,qr[i].z)-zz+1;
    88         cdq1(0,nq-1);
    89         for(int i=0; i<tot; ++i)printf("%d
    ",ans[i]);
    90     }
    91     return 0;
    92 }
    View Code

    解法二(三重CDQ,无需离散化):

    1)2)3)同解法一,第四步将q2中每个子区间按z坐标从小到大排序,将左区间元素与右区间查询放入qr3中,然后利用类似归并排序求逆序对的方法对qr3中的贡献进行统计

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 const int N=5e5+10;
     5 struct QR {
     6     int f,x,y,z,i;
     7 } qr[N],qr2[N],qr3[N],qr4[N];
     8 int n,ans[N],nq,tot;
     9 
    10 void cdq3(int l,int r) {
    11     if(l==r)return;
    12     int mid=(l+r)>>1;
    13     cdq3(l,mid),cdq3(mid+1,r);
    14     int L=l,R=mid+1,m=0;
    15     for(; R<=r; ++R)if(qr3[R].f) {
    16             for(; L<=mid&&qr3[L].z<=qr3[R].z; ++L)if(!qr3[L].f)m++;
    17             ans[qr3[R].i]+=m*qr3[R].f;
    18         }
    19     L=l,R=mid+1;
    20     for(int i=l; i<=r; ++i) {
    21         if(R>r||(L<=mid&&qr3[L].z<=qr3[R].z))qr4[i]=qr3[L++];
    22         else qr4[i]=qr3[R++];
    23     }
    24     for(int i=l; i<=r; ++i)qr3[i]=qr4[i];
    25 }
    26 
    27 
    28 void cdq2(int l,int r) {
    29     if(l==r)return;
    30     int mid=(l+r)>>1;
    31     cdq2(l,mid),cdq2(mid+1,r);
    32     int L=l,R=mid+1,m=0;
    33     for(; R<=r; ++R)if(qr2[R].f) {
    34             for(; L<=mid&&qr2[L].y<=qr2[R].y; ++L)if(!qr2[L].f)qr3[m++]=qr2[L];
    35             qr3[m++]=qr2[R];
    36         }
    37     if(m>0)cdq3(0,m-1);
    38     L=l,R=mid+1;
    39     for(int i=l; i<=r; ++i) {
    40         if(R>r||(L<=mid&&qr2[L].y<=qr2[R].y))qr3[i]=qr2[L++];
    41         else qr3[i]=qr2[R++];
    42     }
    43     for(int i=l; i<=r; ++i)qr2[i]=qr3[i];
    44 }
    45 
    46 void cdq1(int l,int r) {
    47     if(l==r)return;
    48     int mid=(l+r)>>1;
    49     cdq1(l,mid),cdq1(mid+1,r);
    50     int L=l,R=mid+1,m=0;
    51     for(; R<=r; ++R)if(qr[R].f) {
    52             for(; L<=mid&&qr[L].x<=qr[R].x; ++L)if(!qr[L].f)qr2[m++]=qr[L];
    53             qr2[m++]=qr[R];
    54         }
    55     if(m>0)cdq2(0,m-1);
    56     L=l,R=mid+1;
    57     for(int i=l; i<=r; ++i) {
    58         if(R>r||(L<=mid&&qr[L].x<qr[R].x))qr2[i]=qr[L++];
    59         else qr2[i]=qr[R++];
    60     }
    61     for(int i=l; i<=r; ++i)qr[i]=qr2[i];
    62 }
    63 
    64 int main() {
    65     int T;
    66     scanf("%d",&T);
    67     while(T--) {
    68         nq=tot=0;
    69         memset(ans,0,sizeof ans);
    70         scanf("%d",&n);
    71         for(int i=0; i<n; ++i) {
    72             int f;
    73             scanf("%d",&f);
    74             if(f==1) {
    75                 int x,y,z;
    76                 scanf("%d%d%d",&x,&y,&z);
    77                 qr[nq++]= {0,x,y,z,0};
    78             } else {
    79                 int x1,y1,z1,x2,y2,z2;
    80                 scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
    81                 qr[nq++]= {1,x2,y2,z2,tot};
    82                 qr[nq++]= {-1,x1-1,y2,z2,tot};
    83                 qr[nq++]= {-1,x2,y1-1,z2,tot};
    84                 qr[nq++]= {-1,x2,y2,z1-1,tot};
    85                 qr[nq++]= {1,x1-1,y1-1,z2,tot};
    86                 qr[nq++]= {1,x2,y1-1,z1-1,tot};
    87                 qr[nq++]= {1,x1-1,y2,z1-1,tot};
    88                 qr[nq++]= {-1,x1-1,y1-1,z1-1,tot++};
    89             }
    90         }
    91         cdq1(0,nq-1);
    92         for(int i=0; i<tot; ++i)printf("%d
    ",ans[i]);
    93     }
    94     return 0;
    95 }
    View Code

    两种解法复杂度均为O(nlog3n),但解法二比解法一常数大很多,这道题可以勉强A掉,而同样思路的BZOJ3262用同样的方法就会被卡掉。

  • 相关阅读:
    利用FT232实现USB转串口
    用例图
    Flash与EEPROM
    spring -boot定时任务 quartz 基于 MethodInvokingJobDetailFactoryBean 实现
    得到中文首字母
    删除目录
    数字格式化工具
    Md5加密
    Double类型的数值 在写入excel时 如何去掉 科学计算法的 后面数值+ E的 情况
    数值的比较
  • 原文地址:https://www.cnblogs.com/asdfsag/p/10269495.html
Copyright © 2011-2022 走看看