• 并不对劲的cdq分治解三维偏序


    为了反驳隔壁很对劲的太刀流,并不对劲的片手流决定与之针锋相对,先一步发表cdq分治解三维偏序。

    很对劲的太刀流在这里-> 

    参照一、二维偏序的方法,会发现一位偏序就是直接排序,可以看成通过排序使第一维无效。二维偏序是排序+树状数组,就是先通过排序消除了第一维的影响,再通过树状数组进行统计。那么以此类推,三位偏序应该就是树套树状数组…啊不对,是先通过排序消除第一维的影响,再通过【某种方法】消除第二维的影响,再用树状数组统计。

    传说中的【某种方法】就是cdq分治,它是一种通过计算前一半对后一半的影响的降维手段。

    具体来说,假设三维分别是x,y,z,先按x排序。分治时每次将前半边、后半边分别按y排序。虽然现在x的顺序被打乱了,但是前半边还是都小于后半边的,所以要是只计算前半边对后半边的偏序关系,是不会受到x的影响的。维护后一半的指针i,前一半的指针j,每次将i后移一位时,若y[j]<=y[i]则不断后移j,并不断将z[j]加入树状数组。然后再查询树状数组中有多少数小于等于z[i]。 最后要清空树状数组。

    还有“偏序问题中出现了完全相同的要把它们合并”、“清空树状数组时要减回去否则时间超限”、“前大括号必须放在下面“这些细节在此就不提了。

    然后就会发现,一维偏序也可以cdq(虽然大部分人叫它归并排序)、树状数组做,二维偏序也可以cdq做。也就是说,这些降维手段用在第几维都可以。那么会不会有n维偏序,cdq套cdq什么的呢?据说那样复杂度就会在n logkn,还不如n^2暴力枚举。

    其实cdq应该不会只局限于偏序问题,也许会有整体二分之类的的离线方法是参照cdq的算出前一半对后一半的影响这种思想呢?

    不过强制在线就GG了。

    垃圾太刀!!!

    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define maxn 100010
    #define maxk 200010
    #define ll long long 
    using namespace std;
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(isdigit(ch)==0 && ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(int x)
    {
        int f=0;char ch[20];
        if(!x){puts("0");return;}
        if(x<0){putchar('-');x=-x;}
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        putchar('
    ');
    }
    typedef struct node
    {
        int x,y,z,ans,w;    
    }stnd;
    stnd a[maxn],b[maxn];
    int n,cnt[maxk];
    int k,n_;
    bool cmpx(stnd u,stnd v)
    {
        if(u.x==v.x)
        {
            if(u.y==v.y)
                return u.z<v.z;
            return u.y<v.y;
        }
        return u.x<v.x;
    }
    bool cmpy(stnd u,stnd v)
    {
        if(u.y==v.y)
            return u.z<v.z;
        return u.y<v.y;
    }
    struct treearray
    {
        int tre[maxk],kk;
        int lwbt(int x){return x&(-x);}
        int ask(int i){int ans=0; for(;i;i-=lwbt(i))ans+=tre[i];return ans;}
        void add(int i,int k){for(;i<=kk;i+=lwbt(i))tre[i]+=k;}
    }t;
    void cdq(int l,int r)
    {
        if(l==r)return;
        int mid=(l+r)>>1;
        cdq(l,mid);cdq(mid+1,r);
        sort(a+l,a+mid+1,cmpy);
        sort(a+mid+1,a+r+1,cmpy);
        int i=mid+1,j=l;
        for(;i<=r;i++)
        {
            while(a[j].y<=a[i].y && j<=mid)
                t.add(a[j].z,a[j].w),j++;
            a[i].ans+=t.ask(a[i].z);
        }
        for(i=l;i<j;i++)
            t.add(a[i].z,-a[i].w);
    }
    int main()
    {
        n_=read(),k=read();t.kk=k;
        for(int i=1;i<=n_;i++)
            b[i].x=read(),b[i].y=read(),b[i].z=read();
        sort(b+1,b+n_+1,cmpx);
        int c=0;
        for(int i=1;i<=n_;i++)
        {
            c++;
            if(b[i].x!=b[i+1].x || b[i].y!=b[i+1].y || b[i].z!=b[i+1].z )
                a[++n]=b[i],a[n].w=c,c=0;
        } 
        cdq(1,n);     
        for(int i=1;i<=n;i++)
            cnt[a[i].ans+a[i].w-1]+=a[i].w;
        for(int i=0;i<n_;i++)
            write(cnt[i]);
        return 0;
    }
    并不对劲的cdq

    宣传一波电教(现在是电教G了(现在是电教X了(现在是电教XX了))),欢迎加入。

  • 相关阅读:
    科技小论文
    一线架构—细化架构
    python20.04.10
    软件架构总结
    信息领域热词分析
    架构即未来阅读笔记二
    构架即未来阅读笔记一
    科技小论文之软件质量
    Pre-architecture的需求
    软件质量
  • 原文地址:https://www.cnblogs.com/xzyf/p/8466293.html
Copyright © 2020-2023  润新知