離線演算法入門——CDQ分治
阿新 • • 發佈:2021-07-06
離線演算法入門——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; }