luogu P2163 [SHOI2007]园丁的烦恼

luogu P2163 [SHOI2007]园丁的烦恼

题目大意

给出平面上n个点,m个询问,每次询问一个矩阵内的点数
就是二维数点问题

题解

可以先把一个矩阵的询问转换为四个前缀和询问的形式
然后就是二维偏序问题
由于我懒得写树状数组+离散化,于是写了个CDQ分治

code:


#include<bits/stdc++.h>
#define N 4000005
using namespace std;
struct A{
	int x, y, id, o;
}a[N], b[N];
int cmp1(A x, A y){
	if(x.x != y.x) return x.x < y.x;
	if(x.y != y.y) return x.y < y.y;
	return x.id < y.id;
}
int n, m, ANS[N];
void cdq(int l, int r){
	if(l == r) return;
	int mid = (l + r) >> 1;
	cdq(l, mid), cdq(mid + 1, r);
	int pos = l - 1, ans = 0, t = 0;
	for(int i = mid + 1; i <= r; i ++){
		if(a[i].id == 0) continue;
		while(a[pos + 1].y <= a[i].y && pos + 1 <= mid){
			pos ++;
			if(a[pos].id == 0) ans ++;
		}
		ANS[a[i].id] += a[i].o * ans;
	}
	pos = l;
	for(int i = mid + 1; i <= r; i ++){
		while(a[pos].y <= a[i].y && pos <= mid) b[++ t] = a[pos ++];
		b[++ t] = a[i];
	}
	for(int i = pos; i <= mid; i ++) b[++ t] = a[i];
	for(int i = l; i <= r; i ++) a[i] = b[i - l + 1];
}
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i ++) scanf("%d%d", &a[i].x, &a[i].y);
	int t = n;
	for(int i = 1; i <= m; i ++){
		int x, y, xx, yy;
		scanf("%d%d%d%d", &x, &y, &xx, &yy);
		a[++ t].x = xx, a[t].y = yy, a[t].id = i, a[t].o = 1;
		a[++ t].x = xx, a[t].y = y - 1, a[t].id = i, a[t].o = - 1;
		a[++ t].x = x - 1, a[t].y = yy, a[t].id = i, a[t].o = - 1;
		a[++ t].x = x - 1, a[t].y = y - 1, a[t].id = i, a[t].o = 1;
	}
	sort(a + 1, a + 1 + t, cmp1);
	cdq(1, t);
	for(int i = 1; i <= m; i ++) printf("%d\n", ANS[i]);
	return 0;
}
posted @ 2019-09-27 14:46  lahlah  阅读(26)  评论(0编辑  收藏  举报