一道三维偏序的裸题,其实还是很好想的。(像我一样的萌新先戳-->二维偏序
这次来的是三维了,那么怎么办?二维偏序既可以用CDQ分治,又可以用树状数组,那三维偏序,不就一维排序,一维归并,一维树状数组不就行了?
那么就用树状数组替代之前的sum,因为之前sum就是直接累加了,那用树状数组相当于再加了一层筛选。
PS:打cmp的时候,假如不喜欢用a[i].x<a[i].x之类的,最后全部相等时返回false(玄学),不然什么RE,TLE,搞得我一愣一愣的。。。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct flower { int x,y,z,tot,f;//tot表示x、y、z都一样的花有多少朵,f表示对于这种花,没它漂亮的花数 }a[110000];int n,len; void ins(int x,int y,int z) { len++; a[len].x=x;a[len].y=y;a[len].z=z; a[len].tot=1;a[len].f=0; } bool cmp(flower n1,flower n2) { if(n1.x<n2.x)return true; else if(n1.x>n2.x)return false; else if(n1.y<n2.y)return true; else if(n1.y>n2.y)return false; else if(n1.z<n2.z)return true; else if(n1.z>n2.z)return false; return false; } void sc() { int x,y,z; for(int i=1;i<=n;i++) scanf("%d%d%d",&x,&y,&z), ins(x,y,z); sort(a+1,a+len+1,cmp); n=1;//压缩 for(int i=2;i<=len;i++) if(a[n].x==a[i].x&&a[n].y==a[i].y&&a[n].z==a[i].z) a[n].tot++; else a[++n]=a[i]; } //------------sc 第一维排序完成。-------------------- int m,s[210000]; int lowbit(int x){return x&-x;} void add(int x,int k) { while(x<=m) { s[x]+=k; x+=lowbit(x); } } int getsum(int x) { int ans=0; while(x>=1) { ans+=s[x]; x-=lowbit(x); } return ans; } //-----------树状数组解决第三维-------------- flower t[110000]; void cdq(int l,int r)//归并解决第二维,顺便调用树状数组 { if(l==r)return ; int mid=(l+r)/2; cdq(l,mid);cdq(mid+1,r); int i=l,j=mid+1,p=l; while(i<=mid&&j<=r) { if(a[i].y<=a[j].y) add(a[i].z,a[i].tot), t[p++]=a[i++]; else a[j].f+=getsum(a[j].z), t[p++]=a[j++]; } while(i<=mid)add(a[i].z,a[i].tot), t[p++]=a[i++]; while(j<=r)a[j].f+=getsum(a[j].z), t[p++]=a[j++]; for(int i=l;i<=mid;i++)add(a[i].z,-a[i].tot);//清空树状数组,这个如果打memset,每重for都一个O(n)会挂 for(int i=l;i<=r;i++)a[i]=t[i]; } //-------cdq-------------- int ans[110000]; int main() { scanf("%d%d",&n,&m); sc(); memset(s,0,sizeof(s)); cdq(1,n); memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++)ans[a[i].f+a[i].tot-1]+=a[i].tot;//全部相等,相互之间也算自己更加漂亮 for(int i=0;i<len;i++)printf("%d ",ans[i]); return 0; }