C99 CDQ 分治+前缀和 P3755 [CQOI2017] 老C的任务

视频链接:C99 CDQ 分治+前缀和 P3755 [CQOI2017] 老C的任务_哔哩哔哩_bilibili

 

 

 Luogu P3755 [CQOI2017] 老C的任务

// CDQ分治(归并排序)+前缀和 O(nlogn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define mid (l+r>>1)
typedef long long LL;
const int N=500005;
int n,m,k,x1,y1,x2,y2,p;
LL ans[N];
struct E{
  int x,y,z;     //z=0:原始点,z=1:查询点
  int p,id,sign; //id:查询编号,sign:区间和符号
  LL sum;        //前缀和
  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;
  }
}a[N],b[N];

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; LL s=0;
  while(i<=mid&&j<=r){
    //若ai的坐标在aj的左上方,则把原始点的贡献累加到s
    //否则,把s累加到aj的sum中
    if(a[i].y<=a[j].y)s+=!a[i].z*a[i].p,b[k++]=a[i++];
    else a[j].sum+=s,b[k++]=a[j++];
  }
  while(i<=mid) s+=!a[i].z*a[i].p,b[k++]=a[i++];
  while(j<=r) a[j].sum+=s,b[k++]=a[j++];
  
  for(i=l;i<=r;i++) a[i]=b[i]; //按y排序
}
int main(){
  scanf("%d%d",&n,&m);
  for(k=1;k<=n;k++)
    scanf("%d%d%d",&x1,&y1,&p),a[k]={x1,y1,0,p,0,0};
  for(int i=1;i<=m;i++){ //查询区间拆分为4个点
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    a[++k]={x2,y2,    1,0,i,1};
    a[++k]={x2,y1-1,  1,0,i,-1};    
    a[++k]={x1-1,y2,  1,0,i,-1};
    a[++k]={x1-1,y1-1,1,0,i,1};
  }
  sort(a+1,a+k+1); //按x排序
  CDQ(1,k);        //CDQ分治
  for(int i=1;i<=k;i++) //统计答案
    if(a[i].z) ans[a[i].id]+=a[i].sum*a[i].sign;
  for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}

 

// CDQ分治(归并排序)+前缀和 O(nlognlogn)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define mid (l+r>>1)
typedef long long LL;
const int N=500005;
int n,m,k,x1,y1,x2,y2,p;
LL ans[N];
struct E{
  int x,y,z;     //z=0:原始点,z=1:查询点
  int p,id,sign; //id:查询编号,sign:区间和符号
  LL sum;        //前缀和
}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 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; LL s=0;
  while(j<=r){
    //若ai的坐标在aj的左上方,则把原始点的贡献累加到s
    //否则,把s累加到aj的sum中
    while(i<=mid&&a[i].y<=a[j].y)
      s+=!a[i].z*a[i].p,i++;
    a[j].sum+=s,j++;
  }
}
int main(){
  scanf("%d%d",&n,&m);
  for(k=1;k<=n;k++)
    scanf("%d%d%d",&x1,&y1,&p),a[k]={x1,y1,0,p,0,0};
  for(int i=1;i<=m;i++){ //查询区间拆分为4个点
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    a[++k]={x2,y2,    1,0,i,1};
    a[++k]={x2,y1-1,  1,0,i,-1};    
    a[++k]={x1-1,y2,  1,0,i,-1};
    a[++k]={x1-1,y1-1,1,0,i,1};
  }
  sort(a+1,a+k+1,cmpx); //按x排序
  CDQ(1,k);        //CDQ分治
  for(int i=1;i<=k;i++) //统计答案
    if(a[i].z) ans[a[i].id]+=a[i].sum*a[i].sign;
  for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}

 

posted @ 2024-03-10 13:44  董晓  阅读(122)  评论(0编辑  收藏  举报