• 天使玩偶:CDQ分治


    这道好(du)题(liu)还是很不错的 挺锻炼代码能力和不断优化 卡常的能力的。

    对于 每次询问 我都可以将其分出方向 然后 写 也就是针对于4个方向 左下 左上 右下 右上

    这样的话 就成功转换了问题 求4次 三维偏序即可 水题啊。

    然后 打完代码 就提交 T飞了

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<ctime>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdlib>
    #include<cctype>
    #include<utility>
    #include<queue>
    #include<deque>
    #include<vector>
    #include<stack>
    #include<algorithm>
    #include<set>
    #include<bitset>
    #include<map>
    #define INF 2147483646
    #define ll long long
    #define ldb long double
    #define x(i) t[i].x
    #define y(i) t[i].y
    #define k(i) t[i].k
    #define t(i) t[i].t
    #define id(i) t[i].id
    using namespace std;
    char buf[1<<15],*ft,*fs;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        x<0?x=-x,putchar('-'):0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar(10);return;
    }
    const int MAXN=300002,maxn=1000001;
    int n,m,tot,num,cnt;
    struct wy
    {
        int x,y;
        int t,k;
        int id;
    }t[MAXN<<1],tmp[MAXN<<1];
    int ans[MAXN],c[maxn+10];//树状数组维护前缀最大值!
    //注意时间戳也得排序 我的思维漏洞!
    int cmp(wy x,wy y)//左下
    {
        if(x.x==y.x&&x.y==x.y)return x.t<y.t;
        return x.x==y.x?x.y<y.y:x.x<y.x;
    }
    int cmp1(wy x,wy y)//左上
    {
        if(x.x==y.x&&x.y==x.y)return x.t<y.t;
        return x.x==y.x?x.y>y.y:x.x<y.x;
    }
    int cmp2(wy x,wy y)//右下
    {
        if(x.x==y.x&&x.y==x.y)return x.t<y.t;
        return x.x==y.x?x.y<y.y:x.x>y.x;
    }
    int cmp3(wy x,wy y)//右上
    {
        if(x.x==y.x&&x.y==x.y)return x.t<y.t;
        return x.x==y.x?x.y>y.y:x.x>y.x;
    }
    inline int max(int x,int y){return x>y?x:y;}
    void add(int x,int y)
    {
        if(y==INF){for(;x<=maxn;x+=x&(-x))c[x]=-INF;return;}
        for(;x<=maxn;x+=x&(-x))c[x]=max(c[x],y);
        return;
    }
    inline int ask(int x)
    {
        int sum=-INF;
        for(;x;x-=x&(-x))sum=max(sum,c[x]);
        return sum;
    }
    void CDQ(int l,int r,int p)
    {
        if(l==r)return;
        int mid=(l+r)>>1;
        CDQ(l,mid,p);
        CDQ(mid+1,r,p);
        int i=l,j=mid+1;
        if(p==0)
        {
            for(int k=l;k<=r;++k)
            {
                if(j>r||(i<=mid&&t(i)<=t(j)))
                {
                    if(k(i)!=1)add(y(i),x(i)+y(i));
                    tmp[k]=t[i];
                    ++i;
                }
                else
                {
                    if(k(j)==0){tmp[k]=t[j];++j;continue;}
                    //if(id(j)==1)cout<<x(j)<<' '<<y(j)<<endl;
                    int maxx=ask(y(j));
                    if(maxx==-INF){tmp[k]=t[j];++j;continue;}
                    ans[id(j)]=min(ans[id(j)],y(j)+x(j)-maxx);
                    tmp[k]=t[j];
                    ++j;
                }
            }
            for(int k=l;k<=r;k++)
            {
                if(k<=mid&&k(k)!=1)add(y(k),INF);
                t[k]=tmp[k];
            }
        }
        else
        {
            for(int k=l;k<=r;++k)
            {
                if(j>r||(i<=mid&&t(i)<=t(j)))
                {
                    if(k(i)!=1)add(maxn-y(i),x(i)-y(i));
                    tmp[k]=t[i];
                    ++i;
                }
                else
                {
                    if(k(j)==0){tmp[k]=t[j];++j;continue;}
                    int maxx=ask(maxn-y(j));
                    if(maxx==-INF){tmp[k]=t[j];++j;continue;}
                    //cout<<maxx<<endl;
                    ans[id(j)]=min(ans[id(j)],x(j)-y(j)-maxx);
                    tmp[k]=t[j];
                    ++j;
                }
            }
            for(int k=l;k<=r;k++)
                {
                    if(k<=mid&&k(k)!=1)add(maxn-y(k),INF);
                    t[k]=tmp[k];
                }
        }
        return;
    }
    void CDQ1(int l,int r,int p)
    {
        if(l==r)return;
        int mid=(l+r)>>1;
        CDQ1(l,mid,p);
        CDQ1(mid+1,r,p);
        int i=l,j=mid+1;
        if(p==0)
        {
            for(int k=l;k<=r;++k)
            {
                if(j>r||(i<=mid&&t(i)<=t(j)))
                {
                    if(k(i)!=1)add(y(i),y(i)-x(i));
                    tmp[k]=t[i];
                    ++i;
                }
                else
                {
                    if(k(j)==0){tmp[k]=t[j];++j;continue;}
                    //if(id(j)==1)cout<<x(j)<<' '<<y(j)<<endl;
                    int maxx=ask(y(j));
                    if(maxx==-INF){tmp[k]=t[j];++j;continue;}
                    ans[id(j)]=min(ans[id(j)],y(j)-x(j)-maxx);
                    tmp[k]=t[j];
                    ++j;
                }
            }
            for(int k=l;k<=r;k++)
            {
                if(k<=mid&&k(k)!=1)add(y(k),INF);
                t[k]=tmp[k];
            }
        }
        else
        {
            for(int k=l;k<=r;++k)
            {
                if(j>r||(i<=mid&&t(i)<=t(j)))
                {
                    if(k(i)!=1)add(maxn-y(i),-x(i)-y(i));//此处不要想当然的写
                    tmp[k]=t[i];
                    ++i;
                }
                else
                {
                    if(k(j)==0){tmp[k]=t[j];++j;continue;}
                    int maxx=ask(maxn-y(j));
                    if(maxx==-INF){tmp[k]=t[j];++j;continue;}
                    ans[id(j)]=min(ans[id(j)],-maxx-x(j)-y(j));//变形要正确啊!
                    tmp[k]=t[j];
                    ++j;
                }
            }
            for(int k=l;k<=r;k++)
                {
                    if(k<=mid&&k(k)!=1)add(maxn-y(k),INF);
                    t[k]=tmp[k];
                }
        }
        return;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        memset(ans,10,sizeof(ans));
        n=read();m=read();num=n;
        for(int i=1;i<=n;i++)x(i)=read(),y(i)=read();
        for(int i=1;i<=m;i++)
        {
            int p=read();
            x(++num)=read();y(num)=read();
            if(p==2)k(num)=1,id(num)=++cnt;
            t(num)=++tot;
        }
        //for(int i=1;i<=num;i++)cout<<x(i)<<' '<<y(i)<<' '<<t(i)<<' '<<k(i)<<endl;
        for(int i=1;i<=maxn;i++)c[i]=-INF;
        sort(t+1,t+1+num,cmp);//左下
        CDQ(1,num,0);//左下 
        //for(int i=1;i<=cnt;i++)cout<<ans[i]<<endl;
        for(int i=1;i<=maxn;i++)c[i]=-INF;
        sort(t+1,t+1+num,cmp1);//左上
        CDQ(1,num,1);//左上 
        //for(int i=1;i<=cnt;i++)cout<<ans[i]<<endl;
        for(int i=1;i<=maxn;i++)c[i]=-INF;
        sort(t+1,t+1+num,cmp2);//右下
        CDQ1(1,num,0);//右下 
        //for(int i=1;i<=cnt;i++)cout<<ans[i]<<endl;
        for(int i=1;i<=maxn;i++)c[i]=-INF;
        sort(t+1,t+1+num,cmp3);//右上
        CDQ1(1,num,1);//右上
        //for(int i=1;i<=cnt;i++)cout<<ans[i]<<endl;
        for(int i=1;i<=cnt;i++)put(ans[i]);
        return 0;
    }
    View Code

    都别管我我要写4次CDQ 我要sort 4次然后不出意料只拿到50分。

    原因是sort的次数多了 常数是别人的近乎4倍 (有的人一次sort都不做 按照时间直接排)

    然后脑残的写了这么段代码 一直T 照着书上的 标程改了一下是一种比较简洁的做法。

    但是其CDQ的每层都需要sort 一下比较浪费时间但是还是能拿到60分的 开O2 能A呢。

    然后学了一下书上的做法 发现真心简单 代码复杂度 时间复杂度 空间复杂度包括常数都远远低于我

    // luogu-judger-enable-o2
    //#include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<ctime>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdlib>
    #include<cctype>
    #include<utility>
    #include<queue>
    #include<deque>
    #include<vector>
    #include<stack>
    #include<algorithm>
    #include<set>
    #include<bitset>
    #include<map>
    #define INF 2147483646
    #define ll long long
    #define ldb long double
    #define x(i) t[i].x
    #define y(i) t[i].y
    #define t(i) t[i].t
    #define id(i) t[i].id
    using namespace std;
    char buf[1<<15],*ft,*fs;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        x<0?x=-x,putchar('-'):0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar(10);return;
    }
    const int MAXN=600002,maxn=1000010;
    int n,m,cnt,num,tot,h;
    int ans[MAXN],c[maxn],maxx;
    struct wy
    {
        int x,y;
        int t;
        int id;
        friend int operator <(const wy &a,const wy &b)
        {
            return a.x==b.x?a.y<b.y:a.x<b.x;//此时排序不用时间戳(经过实验
            //考虑一次CDQ 分治 时间复杂度 ≈(n+m)*log(n+m)^3左右
        }
    }t[MAXN],tmp[MAXN];
    inline int max(int x,int y){return x>y?x:y;}
    inline int min(int x,int y){return x>y?y:x;}
    inline void add(int x,int y){for(;x<=maxx;x+=x&(-x))c[x]=max(c[x],y);}
    inline int abs(int x){return x<0?-x:x;}
    inline int ask(int x)
    {
        int maxx1=-INF;
        for(;x;x-=x&(-x))maxx1=max(maxx1,c[x]);
        return maxx1;
    }
    inline void remove1(int x)
    {
        for(;x<=maxx;x+=x&(-x))c[x]=-INF;
        return;
    }
    void calculate(int st,int en,int w,int kx,int ky)//属性
    {
        for(int i=st;i!=en;i+=w)
        {
            int yy=(ky==1?tmp[i].y:maxx-tmp[i].y);
            int sum=kx*tmp[i].x+ky*tmp[i].y;
            if(tmp[i].t==1)add(yy,sum);
            else 
            {
                int an=ask(yy);
                if(an==-INF)continue;
                ans[tmp[i].id]=min(ans[tmp[i].id],sum-an);
            }
            //if(tmp[i].id==2)cout<<sum<<' '<<ask(yy)<<endl;
        }
        for(int i=st;i!=en;i+=w)if(tmp[i].t==1)remove1(ky==1?tmp[i].y:maxx-tmp[i].y);
    }
    void CDQ(int l,int r)
    {
        int mid=(l+r)>>1;
        if(l<mid)CDQ(l,mid);
        if(mid+1<r)CDQ(mid+1,r);
        h=0;
        for(int i=l;i<=r;i++)if((i<=mid&&t[i].t==1)||(i>mid&&t[i].t==2))tmp[++h]=t[i];
        sort(tmp+1,tmp+1+h);
        calculate(1,h+1,1,1,1);//左下
        calculate(1,h+1,1,1,-1);//左上
        calculate(h,0,-1,-1,1);//右下
        calculate(h,0,-1,-1,-1);//右上
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        n=read();m=read();num=n;
        for(int i=1;i<=n;++i)
        {
            x(i)=read();
            y(i)=read();
            t(i)=1;
            maxx=max(maxx,y(i));
        }
        for(int i=1;i<=m;++i)
        {
            t(++num)=read();
            x(num)=read();
            y(num)=read();
            id(num)=t(num)==2?++cnt:0;
            maxx=max(maxx,y(num));
        }
        //put(cnt);
        ++maxx;//巧妙一招
        for(int i=1;i<=maxx;++i)c[i]=-INF;
        memset(ans,10,sizeof(ans));
        CDQ(1,num);
        for(int i=1;i<=cnt;i++)put(ans[i]);
        return 0;
    }
    View Code

    比较难受 因为这浪费了我很多的时间 然后最后还是T 开了O2 死T一个点(原因是 我是个NC啊。。。

    开O2 过了不算什么我要不开O2 过

    点开题解发现我的第一个代码的思想及其接近其 题解中跑的最快的。

    所以发现可以不用sort 于是顺利不开O2 第一个代码顺利得到80分。

    发现可以加一个优化是 能不加到树状数组里就不加 到需要的时候再加 还有一些卡常的东西

    最终不开O2 直接A (一直T的那个点是因为下标为0 树状数组原地GG了。。。)

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<ctime>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdlib>
    #include<cctype>
    #include<utility>
    #include<queue>
    #include<deque>
    #include<vector>
    #include<stack>
    #include<algorithm>
    #include<set>
    #include<bitset>
    #include<map>
    #define INF 2147483646
    #define ll long long
    #define ldb long double
    #define x(i) t[i].x
    #define y(i) t[i].y
    #define k(i) t[i].k
    #define t(i) t[i].t
    #define id(i) t[i].id
    #define R register
    using namespace std;
    //char buf[1<<15],*ft,*fs;
    //inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        x<0?x=-x,putchar('-'):0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar(10);return;
    }
    const int maxn=1000010;
    int n,m,tot,num,cnt,maxx1,maxx2;
    struct wy
    {
        int x,y;
        int k,id;
        inline bool operator <(const wy &w)const
        {
            return x<w.x;
        }
    }t[maxn],tmp[maxn],a[maxn];
    int ans[maxn],c[maxn+10];
    inline int max(int x,int y){return x>y?x:y;}
    inline void add(int x,int y)
    {
        
        for(;x<=maxx1;x+=x&(-x))
        {
            if(c[x]>y)break;
            else c[x]=y;
        }
        return;
    }
    inline void remove1(int x)
    {
        for(;x<=maxx1;x+=x&(-x))if(c[x])c[x]=0;
        return;
    }
    inline int ask(int x)
    {
        int sum=-INF;
        for(;x;x-=x&(-x))sum=max(sum,c[x]);
        return sum;
    }
    inline void CDQ(int l,int r)
    {
        int mid=(l+r)>>1;
        if(l<mid)CDQ(l,mid);
        if(r>mid+1)CDQ(mid+1,r);
        R int i=l,j=mid+1;
        for(j=mid+1;j<=r;j++)
        {
            if(k(j)==1)
            {    
                for(;i<=mid&&x(i)<=x(j);i++)
                    if(k(i)==0)add(y(i),x(i)+y(i));
                int maxx=ask(y(j));
                maxx==0?0:ans[id(j)]=min(ans[id(j)],y(j)+x(j)-maxx);
                
            }
        }
        for(j=l;j<i;j++)if(k(j)==0)remove1(y(j));
        i=l,j=mid+1;
        for(R int k=l;k<=r;++k)
        {
            if(j>r||(i<=mid&&t[i]<t[j]))tmp[k]=t[i],++i;
            else tmp[k]=t[j],++j;
        }
        for(R int k=l;k<=r;++k)t[k]=tmp[k];
        return;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        n=read();m=read();num=n;
        for(R int i=1;i<=n;++i){x(i)=read()+1,y(i)=read()+1;maxx1=max(maxx1,y(i));maxx2=max(maxx2,x(i));}
        for(R int i=1;i<=m;++i)
        {
            int p=read();
            x(++num)=read()+1;y(num)=read()+1;
            if(p==2)k(num)=1,id(num)=++cnt;
            maxx1=max(maxx1,y(num));
            maxx2=max(maxx2,x(num));
        }
        ++maxx1;++maxx2;
        for(R int i=1;i<=cnt;++i)ans[i]=INF;
        for(R int i=1;i<=num;++i)a[i]=t[i];
        CDQ(1,num);//左下 
        for(R int i=1;i<=num;++i)t[i]=a[i],y(i)=maxx1-y(i);
        CDQ(1,num);//左上 
        for(R int i=1;i<=num;++i)t[i]=a[i],x(i)=maxx2-x(i);
        CDQ(1,num);//右下 
        for(R int i=1;i<=num;++i)t[i]=a[i],x(i)=maxx2-x(i),y(i)=maxx1-y(i);
        CDQ(1,num);//右上
        for(R int i=1;i<=cnt;++i)put(ans[i]);
        return 0;
    }
    View Code

    当然 为了能够完美的A掉这道题 我决定去学一个更强的东西 KD-tree.

    然后在抄了20min代码后觉定放弃 尧神说没多大卵用。。。

    所以这篇博文到此啦,关键是不断优化的思想 少开O2

  • 相关阅读:
    readLine读取socket流的时候产生了阻塞
    Netty开发UDP协议
    Netty关闭客户端
    GIT 回退出错 Unlink of file 'xx' failed. Should I try again? (y/n) 解决办法
    linux 安全狗安装问题
    linux连接mysql命令
    CentOS7 64位下MySQL5.7安装与配置(YUM)
    nginx已经启动 无法访问页面
    Linux系统下我的/etc/sysconfig/路径下无iptables文件
    CentOS 7 下安装 Nginx
  • 原文地址:https://www.cnblogs.com/chdy/p/10512077.html
Copyright © 2020-2023  润新知