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]的贡献.逆序跑一遍后缀和后正序输出.

posted @ 2019-02-19 16:27  zzuqy  阅读(998)  评论(0编辑  收藏  举报