zoukankan      html  css  js  c++  java
  • CDQ分治,二维数点与三维数点,p1357与p2026与p2027与p2028与p2029

      多方查找找到了2008年陈丹琪引入CDQ分治的 从《Cash》谈一类分治算法的应用.doc ,CDQ分治的名字由来也是她.

      什么叫CDQ分治呢?来看一道二维数点题p1357.

      

      看了一眼题,我会树状数组!

      现在拿它来引入CDQ分治.先全部按照x排序,由于区间[mid+1,r]不会再对区间[l,mid]有贡献,对于区间[l,r]内的贡献都可以分三步进行.

      1.算区间[l,mid]内部相互的贡献

      2.算区间[mid+1,r]内部相互的贡献

      3.算[l,mid]对于[mid+1,r]的贡献

      现在考虑如何更快的计算第3步?假设1,2步后,两个小区间内部变成了按y排序的,我们像归并一样的把两个小区间按y合并成一个大区间并得到[l,mid]对于[mid+1,r]的贡献.

      先放一个nlog^2n的算法

    bool Orz(node a,node b)
    {
        return a.x<b.x;
    }
    void CDQ(int l,int r)
    {
        if(l==r)
            return ;//自己对自己当然没贡献了
        int mid=(l+r)/2;
        CDQ(l,mid);
        CDQ(mid+1,r);
        //简陋的树状数组实现贡献统计
        for(int i=l;i<=mid;i++)//怎么还用树状数组啊?
            add(o[i].y,1);
        for(int i=mid+1;i<=r;i++)
            ans[o[i].i]+=ask(o[i].y);//算贡献
        for(int i=l;i<=mid;i++)//怎么又减回去了啊?
            add(o[i].y,-1);
        sort(o+l,o+r+1);//简陋的sort排序
    }
    int main()
    {
        freopen("123.in","r",stdin);
        n=read();
        for(i=1;i<=n;i++)
        {
            o[i].x=read();
            o[i].y=read();
            o[i].i=i;//记录原始位置
        }
        sort(o+1,o+1+n,Orz);
        CDQ(1,n);//调用分治
        for(i=1;i<=n;i++)
            cout<<ans[i]<<endl;
    }
    简陋的CDQ分治

      再放一个好看的

    struct node
    {
        int x,y;
        int i;
    }o[60010],temp[60010];
    int ans[60010];
    int i,n;
    inline bool Orz(node a,node b)
    {
        return a.x==b.x?a.y<b.y:a.x<b.x;
    }
    inline void CDQ(int l,int r)
    {
        if(l==r)
            return ;//自己对自己当然没贡献了
        int mid=(l+r)/2;
        CDQ(l,mid);
        CDQ(mid+1,r);
        int a=l,b=mid+1,tot=l;
        for(;a<=mid||b<=r;tot++)//合并区间并统计答案
        {
            if(a<=mid&&o[a].y<=o[b].y||b>r)
            {
                temp[tot]=o[a];
                a++;
            }
            else 
            {
                ans[o[b].i]+=a-l;//统计答案
                temp[tot]=o[b];
                b++;
            }
        }
        for(int i=l;i<=r;i++)
            o[i]=temp[i];
    }
    int main()
    {
        n=read();
        for(i=1;i<=n;i++)
        {
            o[i].x=read();
            o[i].y=read();
            o[i].i=i;//记录原始位置
        }
        sort(o+1,o+1+n,Orz);
        CDQ(1,n);//调用分治
        for(i=1;i<=n;i++)
        {
            write(ans[i]);
            putchar(10);
        }
    }
    正常的CDQ分治

      用CDQ A掉后可以去p2026交一下.可以看到两道题几乎一样,区别在于aibi的范围.但是离散化也能写啊QAQ

      


      然后来看一个三位数点问题.

      首先题目有些不一样了,假设随从i可以完爆f(i)个随从,本题询问的是f()=i的数量.

      然后来做题.

      为了继续套用CDQ的模板,我们可先按照x,y,z为第一,二,三关键字从小到大进行排序,这样可以保证任意区间[l,r]内的右区间不会对左区间产生贡献.为了O(r-l)的决策贡献,我们可以使得CDQ()两个子区间后,每个区间内部都是以y为第一关键字进行排序,然后继续按照归并排序的方法合并两个区间并计算贡献,具体计算方法也不一样了,并且y的单调性并不能保证z的单调性,我们需要树状数组了.

    int i;
    int n,c[200010],ans[100010],cnt[100010];
    struct node
    {
        int x,y,z;
        int i;
    }o[100010],temp[100010];
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    inline void add(int x,int k)
    {
        while(x<=200000)
        {
            c[x]+=k;
            x+=lowbit(x);
        }
    }
    inline int ask(int x)
    {
        int sum=0;
        while(x)
        {
            sum+=c[x];
            x-=lowbit(x);
        }
        return sum;
    }
    inline bool Orz(node a,node b)
    {
        return a.x==b.x?(a.y==b.y?(a.z==b.z?a.i<b.i:a.z<b.z):a.y<b.y):a.x<b.x;
    }
    void CDQ(int l,int r)
    {
        if(l==r)
            return ;
        int mid=(l+r)/2;
        CDQ(l,mid);
        CDQ(mid+1,r);
        int a=l,b=mid+1,tot=l; 
        for(;a<=mid||b<=r;tot++)
        {
            if(a<=mid&&(o[a].y<o[b].y||(o[a].y==o[b].y&&o[a].z<o[b].z)||(o[a].y==o[b].y&&o[a].z==o[b].z&&o[a].x<o[b].x))||b>r)
            {
                temp[tot]=o[a];
                add(o[a].z,1);
                a++;
            }
            else
            {
                ans[o[b].i]+=ask(o[b].z);
                temp[tot]=o[b];
                b++;
            }
        }
        while(a>l)
        {
            a--;
            add(o[a].z,-1);
        }
        for(tot=l;tot<=r;tot++)
            o[tot]=temp[tot];
    }
    
    int main()
    {
        n=read();i=read();
        for(i=1;i<=n;i++)
        {
            o[i].x=read();
            o[i].y=read();
            o[i].z=read();
            o[i].i=i;
        }
        sort(o+1,o+1+n,Orz);
        CDQ(1,n);
        for(i=1;i<=n;i++)
            cnt[ans[i]]++;
        for(i=0;i<n;i++)
        {
            write(cnt[i]);
            putchar(10);
        }
    }
    View Code

      这个代码在洛谷上仍然过不了,在本校oj上倒是跑的很好.这说明我的代码还是很糙...//2019 2 20 14:37

      

      不管了我们继续.


      又有了一道CDQ.看一眼题目,是带修改的离线二维数点,如何来做呢?

      先考虑如何读入.

      当然是仁者见仁智者见智了.反正修改和询问是要平等的放在同一个数组(结构体)里的.我的方法是存在结构体里,并把询问拆成四个(假设x2>=x1,y2>=y1)sum(x2,y2)+sum(x1-1,y1-1)-sum(x2,y1-1)-sum(x1-1,y2).存一个i表示时间戳.并把询问的flag设为1,修改的flag设为0.

      然后可以发现,一个区间查询sum(x,y)等价于 "查询所有时间戳小于它且x小于等于它且y小于等于它的flag=0的点的权和".这个和三维偏序好像啊,CDQ+树状数组A掉.

    int i,T,tx1,tx2,ty1,ty2;
    int n,tot,c[500010];
    struct node
    {
        int x,y;
        int i,sum;
        int flag;
    }o[800010],temp[800010];//操作数*4
    int lowbit(int x)
    {
        return x&(-x);
    }
    inline void add(int x,int k)
    {
        while(x<=n)
        {
            c[x]+=k;
            x+=lowbit(x);
        }
    }
    inline int ask(int x)
    {
        int sum=0;
        while(x)
        {
            sum+=c[x];
            x-=lowbit(x);
        }
        return sum;
    }
    void CDQ(int l,int r)
    {
        if(l==r)
            return ;
        int mid=(l+r)/2,t=l,a=l,b=mid+1;
        CDQ(l,mid);
        CDQ(mid+1,r);
        for(;a<=mid||b<=r;t++)
        {
            if(a<=mid&&o[a].x<=o[b].x||b>r)//如果a可以用且a的x小于等于b的x或b不能用
            {
                temp[t]=o[a];
                if(!o[a].flag)
                    add(o[a].y,o[a].sum);
                a++;
            }
            //else if(b<=r&&o[a].x>o[b].x||a>mid)
            else//如果b的x小于a的x或a不能用
            {
                if(o[b].flag)
                    o[b].sum+=ask(o[b].y);
                temp[t]=o[b];
                b++;
            }
        }
        //从上面的if可以发现y的大小不会影响答案
        for(a=l;a<=mid;a++)
            if(!o[a].flag)
                add(o[a].y,-o[a].sum);
        for(t=l;t<=r;t++)
            o[t]=temp[t];
        return ;
    }
    inline bool Orz(node a,node b)
    {
        return a.i<b.i;
    }
    int main()
    {
        n=read();
        for(T=read();T!=3;T=read())
        {
            tot++;
            if(T==1)
            {
                o[tot].x=read();
                o[tot].y=read();
                o[tot].sum=read();
                o[tot].i=tot;
              //o[tot].flag=0;
            }
            else
            {
                tx1=read();ty1=read();tx2=read();ty2=read();
                //下面的min,max是为了防止不合法数据..
                o[tot].x=min(tx1,tx2)-1;
                o[tot].y=min(ty1,ty2)-1;
                o[tot].i=tot;
                o[tot].flag=1;
                tot++;
                o[tot].x=max(tx1,tx2);
                o[tot].y=max(ty1,ty2);
                o[tot].i=tot;
                o[tot].flag=1;
                tot++;
                o[tot].x=max(tx1,tx2);
                o[tot].y=min(ty1,ty2)-1;
                o[tot].i=tot;
                o[tot].flag=1;
                tot++;
                o[tot].x=min(tx1,tx2)-1;
                o[tot].y=max(ty1,ty2);
                o[tot].i=tot;
                o[tot].flag=1;
            }
        }
        //这道"三维偏序"不需要事先sort了,因为有一维i有序了
        CDQ(1,tot);
        //这里的o一定是以x为第一关键字排列的,第二关键字不太清楚也不太重要
        sort(o+1,o+1+tot,Orz);//恢复原排列
        for(i=1;i<=tot;)
            if(o[i].flag)
            {
                write(o[i].sum+o[i+1].sum-o[i+2].sum-o[i+3].sum);//
                putchar(10);
                i+=4;
            }
            else
                i++;
        return 0;
    }
    View Code

      


      继续继续.

      

      

      看到题目,逆序对?我会树状数组!

      动态的?n^2logn!

      我瞎说的.

      读入的时候进行一番操作,可以继续记录每个点的权值为x,位置为i,被删除的时间戳t(最后也没被删去的设为n+1好了).那么可以算每个点的答案为.x1>x&&i1<i&&t1<=t和x1<x&&i1>i&&t1<=t的数量.可以发现t1=t的那部分重复了.我们需要一个简单容斥.这样一处理就又是三维偏序了?我们可以自豪的说出:我会CDQ!

      具体来说,大家可以先写个n^2的暴力,过样例后再调用CDQ写个暴力,再用CDQ写个更好的算法.

      我也会用一晚上的时间搞出多个版本放在下面.

    int i,tx;
    int n,m,c[100010];
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    inline void add(int x,int k)
    {
        while(x<=n)
        {
            c[x]+=k;
            x+=lowbit(x);
        }
    }
    inline int ask(int x)
    {
        int sum=0;
        while(x)
        {
            sum+=c[x];
            x-=lowbit(x);
        }
        return sum;
    }
    struct node
    {
        int x,i,t;//权值,位置,时间
        int ans;
    }o[100010],temp[100010];
    bool x_(node a,node b)
    {
        return a.x<b.x;
    }
    bool t_(node a,node b)
    {
        return a.t<b.t;
    }
    int main()
    {
        freopen("123.in","r",stdin);
        n=read();m=read();
        for(i=1;i<=n;i++)
        {
            o[i].x=read();
            o[i].i=i;
            o[i].t=m+1;
        }
        sort(o+1,o+1+n,x_);
        for(i=1;i<=m;i++)
        {
            tx=read();
            o[tx].t=i;
        }
        sort(o+1,o+1+n,t_);
        for(int a=1;a<=m;a++)
        {
            for(int b=a+1;b<=n;b++)
            {
                if(o[a].x>o[b].x&&o[a].i<o[b].i||o[a].x<o[b].x&&o[a].i>o[b].i)
                {
                    o[a].ans++;
                }
            }
            //cout<<o[a].ans<<endl;
        }
        for(int a=m+1;a<=n;a++)
        {
            for(int b=a+1;b<=n;b++)
            {
                if(o[a].x>o[b].x&&o[a].i<o[b].i||o[a].x<o[b].x&&o[a].i>o[b].i)
                {
                    o[m+1].ans++;
                }
            }
        }
        for(i=m;i;i--)
        {
            o[i].ans+=o[i+1].ans;
        }
        for(i=1;i<=m;i++)
        {
            cout<<o[i].ans<<endl;
        }
    }
    1
    int i,tx;
    int n,m,c[100010];
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    inline void add(int x,int k)
    {
        while(x<=n)
        {
            c[x]+=k;
            x+=lowbit(x);
        }
    }
    inline int ask(int x)
    {
        int sum=0;
        while(x)
        {
            sum+=c[x];
            x-=lowbit(x);
        }
        return sum;
    }
    struct node
    {
        int x,i,t;//权值,位置,时间
        int ans;
    }o[100010],temp[100010];
    int sum;
    bool x_(node a,node b)
    {
        return a.x<b.x;
    }
    bool t_(node a,node b)
    {
        return a.t<b.t;
    }
    void three()
    {
        for(int a=1;a<=m;a++)
            for(int b=a+1;b<=n;b++)
                if(o[a].x>o[b].x&&o[a].i<o[b].i)
                    o[a].ans++;
        for(int a=1;a<=m;a++)
            for(int b=a+1;b<=n;b++)
                if(o[a].x<o[b].x&&o[a].i>o[b].i)
                    o[a].ans++;
      
    }
    void two(int l,int r)
    {
        sort(o+1,o+1+n,t_);
        sort(o+l,o+r+1,x_);
        for(int a=l;a<=r;a++)
        {
            sum+=a-l-ask(o[a].i);
            add(o[a].i,1);
        }
        memset(c,0,sizeof(c));
    }
    int main()
    {
       // freopen("123.in","r",stdin);
        n=read();m=read();
        for(i=1;i<=n;i++)
        {
            o[i].x=read();
            o[i].i=i;
            o[i].t=m+1;
        }
        sort(o+1,o+1+n,x_);
        for(i=1;i<=m;i++)
        {
            tx=read();
            o[tx].t=i;
        }
        two(m+1,n);
        sort(o+1,o+1+n,t_);
        three();
        sort(o+1,o+1+n,t_);
        o[m+1].ans=sum;
        for(i=m;i;i--)
            o[i].ans+=o[i+1].ans;
        for(i=1;i<=m;i++)
            cout<<o[i].ans<<endl;
    }
    60分
    int sum;
    bool x_(node a,node b)
    {
        return a.x<b.x;
    }
    bool _x(node a,node b)
    {
        return a.x>b.x;
    }
    
    bool t_(node a,node b)
    {
        return a.t<b.t;
    }
    void CDQ1(int l,int r)
    {
        if(l==r)
            return ;
        int mid=(l+r)/2,a=l,b=mid+1,tot=l;
        CDQ1(l,mid);
        CDQ1(mid+1,r);
        for(;a<=mid||b<=r;tot++)
            if(a<=mid&&o[a].x<o[b].x||b>r)
            {
                o[a].ans+=b-mid-1-ask(o[a].i);
                temp[tot]=o[a];
                a++;
            }
            else
            {
                add(o[b].i,1);
                temp[tot]=o[b];
                b++;
            }
        for(b=mid+1;b<=r;b++)
            add(o[b].i,-1);
        for(tot=l;tot<=r;tot++)
            o[tot]=temp[tot];
    }
    void CDQ2(int l,int r)
    {
        if(l==r)
            return ;
        int mid=(l+r)/2,a=l,b=mid+1,tot=l;
        CDQ2(l,mid);
        CDQ2(mid+1,r);
        for(;a<=mid||b<=r;tot++)
            if(a<=mid&&o[a].x>o[b].x||b>r)
            {
                o[a].ans+=ask(o[a].i);
                temp[tot]=o[a];
                a++;
            }
            else
            {
                add(o[b].i,1);
                temp[tot]=o[b];
                b++;
            }
        for(b=mid+1;b<=r;b++)
            add(o[b].i,-1);
        for(tot=l;tot<=r;tot++)
            o[tot]=temp[tot];
    }
    void three()
    {
        CDQ1(1,m);
        /*for(int a=1;a<=m;a++)
            for(int b=a+1;b<=m;b++)
                if(o[a].x>o[b].x&&o[a].i<o[b].i)
                    o[a].ans++;*/
        sort(o+1,o+1+n,t_);
        CDQ2(1,m);
         sort(o+1,o+1+n,t_);
       for(int a=1;a<=m;a++)
            for(int b=m+1;b<=n;b++)
                if(o[a].x>o[b].x&&o[a].i<o[b].i)
                    o[a].ans++;
                
        for(int a=1;a<=m;a++)
            for(int b=m+1;b<=n;b++)
                if(o[a].x<o[b].x&&o[a].i>o[b].i)
                    o[a].ans++;
    }
    void two(int l,int r)
    {
        sort(o+1,o+1+n,t_);
        sort(o+l,o+r+1,x_);
        for(int a=l;a<=r;a++)
        {
            sum+=a-l-ask(o[a].i);
            add(o[a].i,1);
        }
        memset(c,0,sizeof(c));
    }
    int main()
    {
        freopen("123.in","r",stdin);
        n=read();m=read();
        for(i=1;i<=n;i++)
        {
            o[i].x=read();
            o[i].i=i;
            o[i].t=m+1;
        }
        sort(o+1,o+1+n,x_);
        for(i=1;i<=m;i++)
        {
            tx=read();
            o[tx].t=i;
        }
        two(m+1,n);
        sort(o+1,o+1+n,t_);
        three();
        sort(o+1,o+1+n,t_);
        o[m+1].ans=sum;
        for(i=m;i;i--)
            o[i].ans+=o[i+1].ans;
        for(i=1;i<=m;i++)
            cout<<o[i].ans<<endl;
    }
    仍然60分
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<stack>
    #include<queue>
    #include<deque>
    #include<set>
    using namespace std;
    
    char buf[1<<15],*fs,*ft;
    inline char getc(){
      return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:* fs++;
    }
    inline int read(){
        int This=0,F=1; char ch=getc();
        while(ch<'0'||ch>'9'){
            if(ch=='-') F=-1;
            ch=getc();
        }
        while(ch>='0'&&ch<='9'){
            This=(This<<1)+(This<<3)+ch-'0';
            ch=getc();
        }
        return This*F;
    }
    
    inline void write(int x)
    {
        if(x==0)
        {
            putchar('0');
            
            return;
        }
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        int num=0;char ch[16];
        while(x) ch[++num]=x%10+'0',x/=10;
        while(num) putchar(ch[num--]);
    }
    int i,tx;
    int n,m,c[100010];
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    inline void add(int x,int k)
    {
        while(x<=n)
        {
            c[x]+=k;
            x+=lowbit(x);
        }
    }
    inline int ask(int x)
    {
        int sum=0;
        while(x)
        {
            sum+=c[x];
            x-=lowbit(x);
        }
        return sum;
    }
    struct node
    {
        int x,i,t;//权值,位置,时间
        int ans;
    }o[100010],temp[100010];
    int sum;
    bool x_(node a,node b)
    {
        return a.x<b.x;
    }
    bool _x(node a,node b)
    {
        return a.x>b.x;
    }
    
    bool t_(node a,node b)
    {
        return a.t<b.t;
    }
    void CDQ1(int l,int r)
    {
        if(l==r)
            return ;
        int mid=(l+r)/2,a=l,b=mid+1,tot=l;
        CDQ1(l,mid);
        CDQ1(mid+1,r);
        for(;a<=mid||b<=r;tot++)
            if(a<=mid&&o[a].x<o[b].x||b>r)
            {
                o[a].ans+=b-mid-1-ask(o[a].i);
                temp[tot]=o[a];
                a++;
            }
            else
            {
                add(o[b].i,1);
                temp[tot]=o[b];
                b++;
            }
        for(b=mid+1;b<=r;b++)
            add(o[b].i,-1);
        for(tot=l;tot<=r;tot++)
            o[tot]=temp[tot];
    }
    void CDQ2(int l,int r)
    {
        if(l==r)
            return ;
        int mid=(l+r)/2,a=l,b=mid+1,tot=l;
        CDQ2(l,mid);
        CDQ2(mid+1,r);
        for(;a<=mid||b<=r;tot++)
            if(a<=mid&&o[a].x>o[b].x||b>r)
            {
                o[a].ans+=ask(o[a].i);
                temp[tot]=o[a];
                a++;
            }
            else
            {
                add(o[b].i,1);
                temp[tot]=o[b];
                b++;
            }
        for(b=mid+1;b<=r;b++)
            add(o[b].i,-1);
        for(tot=l;tot<=r;tot++)
            o[tot]=temp[tot];
    }
    void three()
    {
        CDQ1(1,m);
        /*for(int a=1;a<=m;a++)
            for(int b=a+1;b<=m;b++)
                if(o[a].x>o[b].x&&o[a].i<o[b].i)
                    o[a].ans++;*/
        sort(o+1,o+1+n,t_);
        CDQ2(1,m);
         sort(o+1,o+1+n,t_);
        
        sort(o+1,o+1+m,x_);
        sort(o+1+m,o+n+1,x_);
        int a=1,b=m+1;
        for(;a<=m||b<=n;)
        {
            if(a<=m&&o[a].x<o[b].x||b>n)
            {
                o[a].ans+=b-m-1-ask(o[a].i);
                a++;
            }
            else
            {
                add(o[b].i,1);
                b++;
            }
        }
        memset(c,0,sizeof(c));
        sort(o+1,o+1+m,_x);
        sort(o+1+m,o+1+n,_x);/*
        sort(o+1,o+1+n,t_);
        for(int a=1;a<=m;a++)
            for(int b=m+1;b<=n;b++)
                if(o[a].x<o[b].x&&o[a].i>o[b].i)
                    o[a].ans++;*/
        for(a=1,b=m+1;a<=m||b<=n;)
        {
            if(a<=m&&o[a].x>o[b].x||b>n)
            {
                o[a].ans+=ask(o[a].i);
                a++;
            }
            else
            {
                add(o[b].i,1);
                b++;
            }
        }
        sort(o+1,o+1+n,t_);
    }
    void two(int l,int r)
    {
        sort(o+1,o+1+n,t_);
        sort(o+l,o+r+1,x_);
        for(int a=l;a<=r;a++)
        {
            sum+=a-l-ask(o[a].i);
            add(o[a].i,1);
        }
        memset(c,0,sizeof(c));
    }
    int main()
    {
       // freopen("123.in","r",stdin);
        n=read();m=read();
        for(i=1;i<=n;i++)
        {
            o[i].x=read();
            o[i].i=i;
            o[i].t=m+1;
        }
        sort(o+1,o+1+n,x_);
        for(i=1;i<=m;i++)
        {
            tx=read();
            o[tx].t=i;
        }
        two(m+1,n);
        sort(o+1,o+1+n,t_);
        three();
        sort(o+1,o+1+n,t_);
        o[m+1].ans=sum;
        for(i=m;i;i--)
            o[i].ans+=o[i+1].ans;
        for(i=1;i<=m;i++)
        {
            write(o[i].ans);
            putchar(10);
        }
    }
    80分!
    long long i,tx;
    long long n,m,c[100010];
    inline long long lowbit(long long x)
    {
        return x&(-x);
    }
    inline void add(long long x,long long k)
    {
        while(x<=n)
        {
            c[x]+=k;
            x+=lowbit(x);
        }
    }
    inline long long ask(long long x)
    {
        long long sum=0;
        while(x)
        {
            sum+=c[x];
            x-=lowbit(x);
        }
        return sum;
    }
    struct node
    {
        long long x,i,t;//权值,位置,时间
        long long ans;
    }o[100010],temp[100010];
    long long sum;
    inline bool x_(node a,node b)
    {
        return a.x<b.x;
    }
    inline bool _x(node a,node b)
    {
        return a.x>b.x;
    }
    inline bool t_(node a,node b)
    {
        return a.t<b.t;
    }
    void CDQ1(long long l,long long r)
    {
        if(l==r)
            return ;
        long long mid=(l+r)/2,a=l,b=mid+1,tot=l;
        CDQ1(l,mid);
        CDQ1(mid+1,r);
        for(;a<=mid||b<=r;tot++)
            if(a<=mid&&o[a].x<o[b].x||b>r)
            {
                o[a].ans+=b-mid-1-ask(o[a].i);
                temp[tot]=o[a];
                a++;
            }
            else
            {
                add(o[b].i,1);
                temp[tot]=o[b];
                b++;
            }
        for(b=mid+1;b<=r;b++)
            add(o[b].i,-1);
        for(tot=l;tot<=r;tot++)
            o[tot]=temp[tot];
    }
    void CDQ2(long long l,long long r)
    {
        if(l==r)
            return ;
        long long mid=(l+r)/2,a=l,b=mid+1,tot=l;
        CDQ2(l,mid);
        CDQ2(mid+1,r);
        for(;a<=mid||b<=r;tot++)
            if(a<=mid&&o[a].x>o[b].x||b>r)
            {
                o[a].ans+=ask(o[a].i);
                temp[tot]=o[a];
                a++;
            }
            else
            {
                add(o[b].i,1);
                temp[tot]=o[b];
                b++;
            }
        for(b=mid+1;b<=r;b++)
            add(o[b].i,-1);
        for(tot=l;tot<=r;tot++)
            o[tot]=temp[tot];
    }
    void three()
    {
        CDQ1(1,m);
        sort(o+1,o+1+n,t_);
        CDQ2(1,m);
         sort(o+1,o+1+n,t_);
        sort(o+1,o+1+m,x_);
        sort(o+1+m,o+n+1,x_);
        long long a=1,b=m+1;
        for(;a<=m||b<=n;)
            if(a<=m&&o[a].x<o[b].x||b>n)
            {
                o[a].ans+=b-m-1-ask(o[a].i);
                a++;
            }
            else
            {
                add(o[b].i,1);
                b++;
            }
        memset(c,0,sizeof(c));
        sort(o+1,o+1+m,_x);
        sort(o+1+m,o+1+n,_x);
        for(a=1,b=m+1;a<=m||b<=n;)
            if(a<=m&&o[a].x>o[b].x||b>n)
            {
                o[a].ans+=ask(o[a].i);
                a++;
            }
            else
            {
                add(o[b].i,1);
                b++;
            }
        sort(o+1,o+1+n,t_);
    }
    void two(long long l,long long r)
    {
        sort(o+1,o+1+n,t_);
        sort(o+l,o+r+1,x_);
        for(long long a=l;a<=r;a++)
        {
            sum+=a-l-ask(o[a].i);
            add(o[a].i,1);
        }
        memset(c,0,sizeof(c));
    }
    int main()
    {
        n=read();m=read();
        for(i=1;i<=n;i++)
        {
            o[i].x=read();
            o[i].i=i;
            o[i].t=m+1;
        }
        sort(o+1,o+1+n,x_);
        for(i=1;i<=m;i++)
        {
            tx=read();
            o[tx].t=i;
        }
        two(m+1,n);
        sort(o+1,o+1+n,t_);
        three();
        sort(o+1,o+1+n,t_);
        o[m+1].ans=sum;
        for(i=m;i;i--)
            o[i].ans+=o[i+1].ans;
        for(i=1;i<=m;i++)
        {
            write(o[i].ans);
            putchar(10);
        }
    }
    开long long就100,最终程序

      最终的版本实现方式:先二维偏序sort+树状数组解决(m,n]内的贡献记在sum里 ,最后给o[m+1].ans,并用两次三维偏序解决[1,n]内部的贡献,再跑一边归并计算出(m,n]对[1,n]的贡献.逆序跑一遍后缀和后正序输出.

  • 相关阅读:
    js 字符串中提取ip地址
    echart lengend 选中事件
    反射与注解
    clientX、clientY、offsetLeft、offsetTop、offsetWidth、offsetHeight
    图片放大和缩小
    拖拽文字辅助线对齐
    文字随着鼠标移动而移动(文字拖拽移动)
    Java 数组转 List 的三种方式及使用场景
    【Docker(二)】Docker镜像、容器、仓库命令详解
    【Docker(一)】走进Docker的第一步
  • 原文地址:https://www.cnblogs.com/qywyt/p/10393684.html
Copyright © 2011-2022 走看看