题解 P2163 [SHOI2007]园丁的烦恼
Posted colazcy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P2163 [SHOI2007]园丁的烦恼相关的知识,希望对你有一定的参考价值。
Solution [SHOI2007]园丁的烦恼
题目大意:给定(n)棵树的坐标,每次询问以((a,b))为左下端点,((c,d))为右下端点的矩形内树的数量
题目大意:常规操作先二维前缀和一下:
记(S_{i,j})为左下端点((0,0)),右上端点((i,j))内的树的数量
然后每组询问的答案就是
(ans = S_{c,d} - S_{a - 1,d} - S_{c,b-1}+S_{a-1,b-1})
我们的点就分为了两类:询问点和修改点
对于每个询问点,我们要求的是(x leq m.x;and;y leq m.y)的点的数量,这就是一个二维偏序问题,直接按(x)排序,然后进行(cdq)分治即可
我们要注意的是排序的顺序,两点(a),(b)
若(a.x = b.x;and;a.y = b.y),我们把修改点放在前面
若(a.x = b.x;and;a.y
eq b.y)我们按(y)排序
若(a.x
eq b.x)我们按(x)排序
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int maxq = 3e6;
struct Ques{
int x,y,opt,id;//opt表示点的类型,1为修改点,0为询问点
bool operator < (const Ques &b)const{//排序
return x == b.x ? (y == b.y ? opt : y < b.y) : x < b.x;
}
}ques[maxq],tmp[maxq];
int ques_tot,ans_tot,ans[maxq];
void cdq(int a,int b){//二维偏序
if(a == b)return;
int mid = (a + b) >> 1;
cdq(a,mid),cdq(mid + 1,b);
int posa = a,posb = mid + 1,pos = a,tot = 0;
while(posa <= mid && posb <= b){
if(ques[posa].y <= ques[posb].y)tot += ques[posa].opt,tmp[pos++] = ques[posa++];
else ans[ques[posb].id] += tot,tmp[pos++] = ques[posb++];
}
while(posa <= mid)tmp[pos++] = ques[posa++];
while(posb <= b)ans[ques[posb].id] += tot,tmp[pos++] = ques[posb++];
for(int i = a;i <= b;i++)ques[i] = tmp[i];
}
int n,m;
int main(){
scanf("%d %d",&n,&m);
for(int x,y,i = 1;i <= n;i++)
scanf("%d %d",&x,&y),ques[++ques_tot] = Ques{x,y,1,0};
for(int a,b,c,d,i = 1;i <= m;i++){//拆点
scanf("%d %d %d %d",&a,&b,&c,&d);
ques[++ques_tot] = Ques{c,d,0,++ans_tot};
ques[++ques_tot] = Ques{c,b - 1,0,++ans_tot};
ques[++ques_tot] = Ques{a - 1,d,0,++ans_tot};
ques[++ques_tot] = Ques{a - 1,b - 1,0,++ans_tot};
}
sort(ques + 1,ques + 1 + ques_tot);
cdq(1,ques_tot);
for(int i = 1;i + 3 <= ans_tot;i += 4)
printf("%d
",ans[i] - ans[i + 1] - ans[i + 2] + ans[i + 3]);
return 0;
}
以上是关于题解 P2163 [SHOI2007]园丁的烦恼的主要内容,如果未能解决你的问题,请参考以下文章
洛谷 - P2163 [SHOI2007]园丁的烦恼(离线二维数点)