C97【模板】CDQ 分治+树状数组 P3810 三维偏序

视频链接:C97【模板】CDQ 分治+树状数组 P3810 三维偏序_哔哩哔哩_bilibili

 

 

 

C78 二维线段树+动态开点 点修+区查 P3810 三维偏序(陌上花开) - 董晓 - 博客园 (cnblogs.com)

Luogu P3810【模板】三维偏序(陌上花开)

// 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]);
}

 

posted @ 2024-02-01 15:29  董晓  阅读(307)  评论(0编辑  收藏  举报