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]的貢獻.逆序跑一遍後綴和後正序輸出.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章