我tm终于把三维偏序调对了
CDQ分治是一种进行计算时的降维手段,简单说大家都知道在进行一维偏序时我们只需要排序,二维偏序则可以用树状数组+排序,这之中树状数组就是一个降维手段,它将二维偏序降维,然后就可以用一维偏序做了。CDQ和树套树也是同理,以听说CDQ可以解决m维偏序,时间复杂度nlog(m-1)n
CDQ的思想主要是分治,然后计算前半部分对后半部分产生的影响所以说常规分治其实是恰好前半部分对后半部分没影响的CDQ??
下面就是代码(三维偏序),思路是排序一维,CDQ一维,CDQ中用树状数组统计第三维
重点:
1.CDQ分治中树状数组一定不要memset!把树状数组的加法减回去就好了;
2.排序后再记一次rank可以大幅降低编程难度;
3.对于重复数据我们可以记录每个数据排序最靠后的一个,它的答案就是所有这个数据的答案(想想为什么)
代码略丑
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #define lowbit(x) (x&(-x)) using namespace std; struct data { int x,y,z,num,num2; bool operator < (const data &a) const { if(x==a.x) { if(y==a.y) return z<a.z; return y<a.y; } return x<a.x; } bool operator != (const data &a) const { return ((x!=a.x)||(y!=a.y)||(z!=a.z)); } }P[100010]; bool cmp(data a,data b) { if(a.y==b.y) { return a.num2<b.num2; } return a.y<b.y; } int n,k; int c[450010],ans[100010],ans2[100010]; int to[100010]; void add(int p,int x){for(int i=p;i<=400010;i+=lowbit(i))c[i]+=x;} int query(int p){int tmp=0;for(int i=p;i>=1;i-=lowbit(i))tmp+=c[i];return tmp;} void cdq(int l,int r) { if(l==r) return; int mid=(l+r)/2; data mi=P[mid]; cdq(l,mid);cdq(mid+1,r); sort(P+l,P+r+1,cmp); for(int i=l;i<=r;i++) { if(P[i].num2<=mi.num2) { add(P[i].z,1); } else { ans[P[i].num]+=query(P[i].z); } } for(int i=l;i<=r;i++) { if(P[i].num2<=mi.num2) add(P[i].z,-1); } return; } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { P[i].num=i; scanf("%d%d%d",&P[i].x,&P[i].y,&P[i].z); } sort(P+1,P+n+1); P[n+1].x=-1; int flag=1; for(int i=1;i<=n;i++) { P[i].num2=i; if(P[i]!=P[i+1]) { for(int j=flag;j<=i;j++) to[P[j].num]=P[i].num; flag=i+1; } } cdq(1,n); for(int i=1;i<=n;i++) { ans2[ans[to[i]]]++; } for(int i=0;i<n;i++) { printf("%d ",ans2[i]); } }