C97【模板】CDQ 分治+树状数组 P3810 三维偏序
视频链接:C97【模板】CDQ 分治+树状数组 P3810 三维偏序_哔哩哔哩_bilibili
C78 二维线段树+动态开点 点修+区查 P3810 三维偏序(陌上花开) - 董晓 - 博客园 (cnblogs.com)
// CDQ分治(归并排序)+树状数组 O(nlognlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define lowbit(x) x&-x #define mid (l+r>>1) const int N=100005,M=200005; int n,m; int s[M],ans[N]; struct E{ int x,y,z; int cnt,s; //cnt:重复元素个数,s:≤ai的个数 bool operator==(const E& t) const{ return x==t.x&&y==t.y&&z==t.z; } }a[N]; bool cmpx(E &a,E &b){ //按x排序 if(a.x!=b.x) return a.x<b.x; if(a.y!=b.y) return a.y<b.y; return a.z<b.z; } bool cmpy(E &a,E &b){ //按y排序 return a.y<b.y; } void change(int x,int k){ //向后修 while(x<=M) s[x]+=k, x+=lowbit(x); } int query(int x){ //向前查 int t=0; while(x) t+=s[x], x-=lowbit(x); return t; } void CDQ(int l,int r){ //CDQ分治(归并排序) if(l==r) return; CDQ(l,mid); CDQ(mid+1,r); //按x分裂 int i=l,j=mid+1; while(i<=mid&&j<=r){ if(a[i].y<=a[j].y) change(a[i].z,a[i].cnt),i++; //zi加入树状数组 else a[j].s+=query(a[j].z),j++;//累计<=zj的个数 } while(i<=mid) change(a[i].z,a[i].cnt),i++; while(j<=r) a[j].s+=query(a[j].z),j++; for(j=l;j<=mid;j++)change(a[j].z,-a[j].cnt);//清空树状数组 sort(a+l,a+r+1,cmpy); //按y排序 } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].cnt=1; } sort(a+1,a+n+1,cmpx); //按x排序 int k=1; for(int i=2;i<=n;i++){ if(a[i]==a[k]) a[k].cnt++; else a[++k]=a[i]; //去重 } CDQ(1,k); //CDQ分治 for(int i=1;i<=k;i++) //统计答案 ans[a[i].s+a[i].cnt-1]+=a[i].cnt; for(int i=0;i<n;i++) printf("%d\n",ans[i]); }
// CDQ分治(归并排序)+树状数组 O(nlognlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define lowbit(x) x&-x #define mid (l+r>>1) const int N=100005,M=200005; int n,m; int s[M],ans[N]; struct E{ int x,y,z; int cnt,s; //cnt:重复元素个数,s:≤ai的个数 bool operator<(const E& t) const{ if(x!=t.x) return x<t.x; if(y!=t.y) return y<t.y; return z<t.z; } bool operator==(const E& t) const{ return x==t.x&&y==t.y&&z==t.z; } }a[N],b[N]; void change(int x,int v){ //向后修 for(;x<M;x+=lowbit(x)) s[x]+=v; } int query(int x){ //向前查 int t=0; for(;x;x-=lowbit(x)) t+=s[x]; return t; } void CDQ(int l,int r){ //CDQ分治(归并排序) if(l==r) return; CDQ(l,mid); CDQ(mid+1,r); //按x分裂 int i=l,j=mid+1,k=l; while(i<=mid&&j<=r){ if(a[i].y<=a[j].y) change(a[i].z,a[i].cnt),b[k++]=a[i++]; //zi加入树状数组 else a[j].s+=query(a[j].z),b[k++]=a[j++]; //累计<=zj的个数 } while(i<=mid) change(a[i].z,a[i].cnt),b[k++]=a[i++]; while(j<=r) a[j].s+=query(a[j].z),b[k++]=a[j++]; for(j=l;j<=mid;j++) change(a[j].z,-a[j].cnt); //清空树状数组 for(i=l;i<=r;i++) a[i]=b[i]; //按y排序 } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].cnt=1; } sort(a+1,a+n+1); //按x排序 int k=1; for(int i=2;i<=n;i++){ if(a[i]==a[k]) a[k].cnt++; else a[++k]=a[i]; //去重 } CDQ(1,k); //CDQ分治 for(int i=1;i<=k;i++) //统计答案 ans[a[i].s+a[i].cnt-1]+=a[i].cnt; for(int i=0;i<n;i++) printf("%d\n",ans[i]); }
// CDQ分治(归并排序)+树状数组 O(nlognlogn) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define lowbit(x) x&-x #define mid (l+r>>1) const int N=100005,M=200005; int n,m; int s[M],ans[N]; struct E{ int x,y,z; int cnt,s; //cnt:重复元素个数,s:≤ai的个数 bool operator==(const E& t) const{ return x==t.x&&y==t.y&&z==t.z; } }a[N]; bool cmpx(E &a,E &b){ //按x排序 if(a.x!=b.x) return a.x<b.x; if(a.y!=b.y) return a.y<b.y; return a.z<b.z; } bool cmpy(E &a,E &b){ //按y排序 return a.y<b.y; } void change(int x,int k){ //向后修 while(x<=M) s[x]+=k, x+=lowbit(x); } int query(int x){ //向前查 int t=0; while(x) t+=s[x], x-=lowbit(x); return t; } void CDQ(int l,int r){ //CDQ分治(归并排序) if(l==r) return; CDQ(l,mid); CDQ(mid+1,r); //按x分裂 sort(a+l,a+mid+1,cmpy); sort(a+mid+1,a+r+1,cmpy); //按y排序 int i=l,j=mid+1; while(j<=r){ while(i<=mid && a[i].y<=a[j].y) change(a[i].z,a[i].cnt),i++; //zi加入树状数组 a[j].s+=query(a[j].z),j++; //累计<=zj的个数 } for(j=l;j<i;j++)change(a[j].z,-a[j].cnt); //清空树状数组 } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); a[i].cnt=1; } sort(a+1,a+n+1,cmpx); //按x排序 int k=1; for(int i=2;i<=n;i++){ if(a[i]==a[k]) a[k].cnt++; else a[++k]=a[i]; //去重 } CDQ(1,k); //CDQ分治 for(int i=1;i<=k;i++) //统计答案 ans[a[i].s+a[i].cnt-1]+=a[i].cnt; for(int i=0;i<n;i++) printf("%d\n",ans[i]); }