1. 程式人生 > >[模板] CDQ分治&&BZOJ3262:陌上花開

[模板] CDQ分治&&BZOJ3262:陌上花開

簡介

CDQ分治是分治的一種, 可以看做歸併排序的擴充套件, 利用離線將一些 \(O(n)\) 的暴力優化到 \(O(log n)\).

它可以用來頂替一些高階(log)資料結構等.

一般地, CDQ分治分為三部分:

  1. 遞迴左右區間
  2. 統計左區間對右區間的貢獻
  3. 合併整個區間

或者:

  1. 遞迴左右區間
  2. 分別合併左, 右區間
  3. 統計左區間對右區間的貢獻

這兩種方法一般來說是等價的.

詳見程式碼.

程式碼

利用cdq分治求三維偏序.

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;

//---------------------------------------
const int nsz=1e5+5,ksz=2e5+5;
int n0,n=0,k,ans[nsz];

struct tl{int a,b,c,cnt,res;}line[nsz]{{-1,-1,-1,0,0}};
bool cmpa(tl a,tl b){return a.a!=b.a?a.a<b.a:a.b!=b.b?a.b<b.b:a.c<b.c;}
bool cmpb(tl a,tl b){return a.b!=b.b?a.b<b.b:a.c<b.c;}
bool eq(tl a,tl b){return a.a==b.a&&a.b==b.b&&a.c==b.c;}

//bit
int bit[ksz];
#define lb(p) ((p)&(-(p)))
void add(int p,int v){while(p<=k)bit[p]+=v,p+=lb(p);}
int qu(int p){
    int res=0;
    while(p)res+=bit[p],p-=lb(p);
    return res;
}

//第一種方式
tl l2[nsz];
void cdq(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    cdq(l,mid);
    cdq(mid+1,r);
    int pl=l,pr=mid+1;
    rep(i,l,r){
        if(pl<=mid&&(pr==r+1||line[pl].b<=line[pr].b)) //important: <=
            add(line[pl].c,line[pl].cnt),l2[i]=line[pl++];
        else
            line[pr].res+=qu(line[pr].c),l2[i]=line[pr++];
    }
    rep(i,l,mid)add(line[i].c,-line[i].cnt);
    rep(i,l,r)line[i]=l2[i];
}

//第二種方式
void cdq1(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    cdq1(l,mid);
    cdq1(mid+1,r);
    sort(line+l,line+mid+1,cmpb);
    sort(line+mid+1,line+r+1,cmpb);
    int p=l;
    rep(i,mid+1,r){
        while(line[p].b<=line[i].b&&p<=mid)add(line[p].c,line[p].cnt),++p;//important: <=
        line[i].res+=qu(line[i].c);
    }
    rep(i,l,p-1)add(line[i].c,-line[i].cnt);
}



int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>n0>>k;
    rep(i,1,n0)cin>>line[i].a>>line[i].b>>line[i].c;
    sort(line+1,line+n0+1,cmpa);
    
    rep(i,1,n0){
        if(!eq(line[i],line[n]))line[++n]=line[i];
        ++line[n].cnt;
    }

    cdq(1,n);
//  rep(i,1,n)printf("%d %d %d %d %d\n",line[i].a,line[i].b,line[i].c,line[i].cnt,line[i].res);

    rep(i,1,n)ans[line[i].res+line[i].cnt-1]+=line[i].cnt;
    rep(i,0,n0-1)cout<<ans[i]<<'\n';
    return 0;
}