多方查找找到了2008年陈丹琪引入CDQ分治的 从《Cash》谈一类分治算法的应用.doc ,CDQ分治的名字由来也是她.
什么叫CDQ分治呢?来看一道二维数点题p1357.
看了一眼题,我会树状数组!
现在拿它来引入CDQ分治.先全部按照x排序,由于区间[mid+1,r]不会再对区间[l,mid]有贡献,对于区间[l,r]内的贡献都可以分三步进行.
1.算区间[l,mid]内部相互的贡献
2.算区间[mid+1,r]内部相互的贡献
3.算[l,mid]对于[mid+1,r]的贡献
现在考虑如何更快的计算第3步?假设1,2步后,两个小区间内部变成了按y排序的,我们像归并一样的把两个小区间按y合并成一个大区间并得到[l,mid]对于[mid+1,r]的贡献.
先放一个nlog^2n的算法
bool Orz(node a,node b) { return a.x<b.x; } void CDQ(int l,int r) { if(l==r) return ;//自己对自己当然没贡献了 int mid=(l+r)/2; CDQ(l,mid); CDQ(mid+1,r); //简陋的树状数组实现贡献统计 for(int i=l;i<=mid;i++)//怎么还用树状数组啊? add(o[i].y,1); for(int i=mid+1;i<=r;i++) ans[o[i].i]+=ask(o[i].y);//算贡献 for(int i=l;i<=mid;i++)//怎么又减回去了啊? add(o[i].y,-1); sort(o+l,o+r+1);//简陋的sort排序 } int main() { freopen("123.in","r",stdin); n=read(); for(i=1;i<=n;i++) { o[i].x=read(); o[i].y=read(); o[i].i=i;//记录原始位置 } sort(o+1,o+1+n,Orz); CDQ(1,n);//调用分治 for(i=1;i<=n;i++) cout<<ans[i]<<endl; }