Loading

离线算法入门——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;
}
posted @ 2021-07-06 20:32  hyl天梦  阅读(114)  评论(0编辑  收藏  举报