C99 CDQ 分治+前缀和 P3755 [CQOI2017] 老C的任务
视频链接:C99 CDQ 分治+前缀和 P3755 [CQOI2017] 老C的任务_哔哩哔哩_bilibili
// 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]); }