1. 程式人生 > 其它 >離線演算法入門——CDQ分治

離線演算法入門——CDQ分治

離線演算法入門——CDQ分治

1 簡介

CDQ 分治只能算作一種方法而非一種通用的演算法,對於一段操作序列,我們從中間分開,先處理左邊,再處理右邊,最後加上左邊對右邊的影響。歸併排序實際上就是一個 CDQ 分治。

2 例題

2.1 三維偏序

連結

我們首先按照第一維從大到小排序。這樣接下來我們只需要考慮第二第三層。考慮 CDQ 分治,如何統計左邊對右邊的貢獻呢?我們可以把兩邊都按照第二維排序,然後用雙指標統計答案。

需要注意的是,如果兩個元素第一維相同,第二維不同,我們需要讓左邊的第二維嚴格小於右邊。否則這個答案就可能統計不上,因為相同的元素如果劃分到一個區域裡可能統計不了答案,我們需要提前去重。

程式碼:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 200010
#define M number
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

int n,k,f[N],tong[N];

struct BIT{
    int p[N];
    inline int lowbit(int x){return x&(-x);}
    inline void add(int x,int val){for(int i=x;i<=k;i+=lowbit(i))p[i]+=val;}
    inline int ask_sum(int x){int ans=0;for(int i=x;i>=1;i-=lowbit(i)) ans+=p[i];return ans;}
};
BIT bit;

struct flower{
    int a,b,c,cnt,ans;
    inline bool operator == (const flower &b) const{
        return (a==b.a)&&(this->b==b.b)&&(c==b.c);
    }
};
flower fl[N];

inline bool cmp1(flower a,flower b){
    if(a.a!=b.a) return a.a<b.a;
    else if(a.b!=b.b) return a.b<b.b;
    else return a.c<b.c;
}

inline bool cmp2(flower a,flower b){
    if(a.b!=b.b) return a.b<b.b;
    else return a.c<b.c;
}

inline void cdq(int l,int r){
    if(l==r) return;
    int mid=(l+r)>>1;
    cdq(l,mid);cdq(mid+1,r);
    sort(fl+l,fl+mid+1,cmp2);
    sort(fl+mid+1,fl+r+1,cmp2);
    int i=l,j=mid+1;
    for(;j<=r;j++){
        while(fl[i].b<=fl[j].b&&i<=mid){
            bit.add(fl[i].c,fl[i].cnt);i++;
        }
        fl[j].ans+=bit.ask_sum(fl[j].c);
    }
    for(int w=l;w<i;w++) bit.add(fl[w].c,-fl[w].cnt);
}

int main(){
    // freopen("my.in","r",stdin);
    // freopen("my.out","w",stdout);
    read(n);read(k);
    for(int i=1;i<=n;i++){
        read(fl[i].a);read(fl[i].b);read(fl[i].c);
    }
    sort(fl+1,fl+n+1,cmp1);
    int tail=0;fl[++tail]=fl[1];fl[tail].cnt=1;
    for(int i=2;i<=n;i++){
        if(fl[i]==fl[i-1]){
            fl[tail].cnt++;
        }
        else fl[++tail]=fl[i],fl[tail].cnt=1;
    }
    cdq(1,tail);
    for(int i=1;i<=tail;i++) tong[fl[i].ans+fl[i].cnt-1]+=fl[i].cnt;
    for(int i=0;i<=n-1;i++) printf("%d\n",tong[i]);
    return 0;
}