• Hdu5126-stars(两次CDQ分治)


    题意: 简化就是有两种操作,一种是插入(x,y,z)这个坐标,第二种是查询(x1,y1,z1)到(x2,y2,z2)(x1<=x2,y1<=y2,z1<=z2)的长方体包含多少个点。

    解析: 将查询分成8个点,离线做,离散化z值,
    两次CDQ,第一次归并排x值,第二次归并排y值,z值用bit树维护更新
    查询。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<string>
    using namespace std;
    const int maxn=9*50000;
    int N,Q,ans[maxn];
    struct node
    {
        int x,y,z,id,s;//(x,y,z)三维坐标,id编号,s代表状态
        node(int x=0,int y=0,int z=0,int id=0,int s=0)
        :x(x),y(y),z(z),id(id),s(s){}
    }A[maxn],B[maxn],C[maxn];//A保存原数组,B保存中间过程,C用于归并排序临时数组
    bool cmpid(const node& a,const node& b){ return a.id<b.id; } //排id
    bool cmpz(const node& a,const node& b){ return a.z<b.z; } //排z值
    int tree[maxn];//bit树实现部分
    int lowbit(int x){ return x&(-x); }
    void Add(int i,int d){ for(;i<maxn;i+=lowbit(i)) tree[i]+=d; }
    int Sum(int i)
    {
        int ret=0;
        for(;i>0;i-=lowbit(i)) ret+=tree[i];
        return ret;
    }
    void CDQ2(int l,int r) //归并排y值,对z值查询更新
    {
        if(l>=r) return;
        int mid=(l+r)/2;
        CDQ2(l,mid);
        CDQ2(mid+1,r);
        int ls=l,rs=mid+1;
        while(rs<=r)
        {
            while(ls<=mid&&B[ls].y<=B[rs].y) //选取y较小的
            {
                if(B[ls].s==0) Add(B[ls].z,1); //如果是0则需要插入bit树
                ls++;
            }
            if(B[rs].s!=0) ans[B[rs].id]+=Sum(B[rs].z)*B[rs].s; //右边的是查询
            rs++;
        }
        while(ls>l) //恢复
        {
            ls--;
            if(B[ls].s==0) Add(B[ls].z,-1);
        }
        ls=l,rs=mid+1;
        for(int i=l;i<=r;i++) //归并排序过程,排y值
        {
            if((ls<=mid&&B[ls].y<=B[rs].y)||rs>r) C[i]=B[ls++];
            else C[i]=B[rs++];
        }
        for(int i=l;i<=r;i++) B[i]=C[i];
    }
    void CDQ1(int l,int r)//归并排x值,选取的过程是时序
    {
        if(l==r) return;
        int mid=(l+r)/2;
        CDQ1(l,mid);
        CDQ1(mid+1,r);
        int ls=l,rs=mid+1,k=0;
        while(rs<=r)
        {
            while(ls<=mid&&A[ls].s!=0) ls++; //前一半而且是查询不管
            while(rs<=r&&A[rs].s==0) rs++; //后一半而且是插入不管
            if(rs>r) break; //这个地方可能难理解,仔细 想一下如果右边已经没有查询的操作了,
                            //剩下的左边的时序绝对比最后一次加到B中的查询的操作时序要大
            if((A[ls].x<=A[rs].x&&ls<=mid)||rs>r) B[k++]=A[ls++];
            else B[k++]=A[rs++];
        }
        if(k>0) CDQ2(0,k-1);  //再一次CDQ
        ls=l,rs=mid+1;
        for(int i=l;i<=r;i++) //归并排序
        {
            if((ls<=mid&&A[ls].x<=A[rs].x)||rs>r) C[i]=A[ls++];
            else C[i]=A[rs++];
        }
        for(int i=l;i<=r;i++) A[i]=C[i];
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            N=0;
            int type,x1,y1,z1,x2,y2,z2;
            scanf("%d",&Q);
            while(Q--)
            {
                scanf("%d",&type);
                if(type==1)
                {
                    scanf("%d%d%d",&x1,&y1,&z1);
                    A[N++]=node(x1,y1,z1,N,0); //要插入的点
                }
                else
                {
                    scanf("%d%d%d",&x1,&y1,&z1);
                    scanf("%d%d%d",&x2,&y2,&z2);
                    A[N++]=node(x2,y2,z2,N,1);   //分成8个查询的点
                    A[N++]=node(x2,y1-1,z2,N,-1);
                    A[N++]=node(x1-1,y2,z2,N,-1);
                    A[N++]=node(x2,y2,z1-1,N,-1);
                    A[N++]=node(x1-1,y1-1,z2,N,1);
                    A[N++]=node(x1-1,y2,z1-1,N,1);
                    A[N++]=node(x2,y1-1,z1-1,N,1);
                    A[N++]=node(x1-1,y1-1,z1-1,N,-1);
                }
            }
            memset(ans,0,sizeof(ans));
            sort(A,A+N,cmpz); //按照z值排序
            int ka=1;
            A[N].z=-1;
            for(int i=0;i<N;i++)
                if(A[i].z!=A[i+1].z) A[i].z=ka++; //离散化
                else A[i].z=ka;
            sort(A,A+N,cmpid); //按照时序排回来
            memset(tree,0,sizeof(tree));
            CDQ1(0,N-1);
            sort(A,A+N,cmpid); //再排回来
            for(int i=0;i<N;i++) //输出答案
            {
                if(A[i].s==0) continue;
                int sum=0;
                for(int j=0;j<8;j++) sum+=ans[i+j];
                printf("%d
    ",sum);
                i+=7;
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    安装vue-cli时-4058报错的解决方法
    Sublime text 3 配置
    Vue项目本地run与build后样式不同,build后样式不生效
    npm run build 打包后,如何运行在本地查看效果(Nginx服务)
    JavaScript(ES6)学习笔记-Set和Map与数组和对象的比较(二)
    JavaScript(ES6)学习笔记-Set和Map数据结构(一)
    Angular
    本地项目与码云上的项目相关联
    获取GitHub上远程分支内容
    MyEclipse
  • 原文地址:https://www.cnblogs.com/wust-ouyangli/p/5772648.html
Copyright © 2020-2023  润新知