[模板] CDQ分治&&BZOJ3262:陌上花開
阿新 • • 發佈:2019-01-12
簡介
CDQ分治是分治的一種, 可以看做歸併排序的擴充套件, 利用離線將一些 \(O(n)\) 的暴力優化到 \(O(log n)\).
它可以用來頂替一些高階(log)資料結構等.
一般地, CDQ分治分為三部分:
- 遞迴左右區間
- 統計左區間對右區間的貢獻
- 合併整個區間
或者:
- 遞迴左右區間
- 分別合併左, 右區間
- 統計左區間對右區間的貢獻
這兩種方法一般來說是等價的.
詳見程式碼.
程式碼
利用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; }