二维数点问题

二维数点问题

二维数点在OI中有着广泛的应用,很多题目正解或其部分分都可以转化为二维数点的模型.

一般性的静态二维数点问题:

给出平面上的(n)个点的坐标(P_i(x_i,y_i)),(Q)次查询,每次查询((a,b,c,d)),表示,求在矩形((a,b),(c,d))中的点数

(a,b,c,d,n <= 10^5)

数据范围都是(10^5)级别的,我们就不能运用前缀和去解决问题了

但是可以运用二维前缀和的思想

我们设(S(x,y))表示((0,0)(x,y))这个矩阵中点的个数

每次询问的答案很明显是

(S(c,d) - S(a - 1,d) - S(c,b - 1) + S(c - 1,d - 1))

我们就将个询问拆成这四部分分解维护

之后用扫描线的思想维护树状数组,大体思路是这样的:

先将所有的点,和我们拆分完成之后的询问全部按照(x)进行排序

(对于(x)这一维)之后每次扫到一个询问的(x),就把当前还剩下的小于等于(x)的点全部加上

加上什么呢,这个点在(y)这一维的贡献(可能有点绕)

就是我们把树状数组的下标看做权值

当前影响的是(1- y)这个范围的点.所以在树状数组上将这个区间的贡献(+1)

例题BZOJ1935/Luogu2163[SHOI2007]园丁的烦恼

就是上面的问题,但是注意一下坐标有((0,0)),而树状数组(0)没有意义,所以将所有坐标整体(+1)

另外这道题坐标范围是(10^7)级别的,按理来说应当对(y)这一维离散化,但是树状数组跑的飞快,就不管了,反正空间不会炸.

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 5e5 + 5;
int c[10000003];
int n,m;
int ans[N];
struct tree{
	int x,y;	
}v[N];
struct ques{
	int x,y;
	int id,opt;	
	ques(int xx = 0,int yy = 0,int num = 0,int o = 0){
		x = xx,y = yy,id = num,opt = o;
	}
}q[N << 2];
inline char nc(){
    #define SIZE 1000000+5
    static char buf[SIZE],*p1 = buf+SIZE,*p2 = buf+SIZE;
    if(p1 == p2){
        p1 = buf;p2 = buf+fread(buf,1,SIZE,stdin);
        if(p1 == p2) return -1;
    }
    return *p1++;
}
inline int read(){
    int x = 0;char ch = nc();int flag = 0;
    while(!isdigit(ch)){
        if(ch == '-') flag = -1;
        ch = nc();
    }
    while(isdigit(ch)){
        x = (x<<1) + (x<<3) + (ch^'0');
        ch = nc();
    }
    if(flag) x = -x;
    return x;
}
inline bool cmp1(tree x,tree y){
	return x.x < y.x;	
}
inline bool cmp2(ques x,ques y){
	return x.x < y.x;
} 
inline void updata(int x,int val){
	for(;x <= n;x += x & -x) c[x] += val;	
}
inline int query(int x){
	int res = 0;
	for(;x;x -= x & -x) res += c[x];
	return res;	
}
int main(){
	int cnt = 0;
	n = read(),m = read();
	for(int i = 1;i <= n;++i)
	v[i].x = read() + 1,v[i].y = read() + 1;
	for(int i = 1;i <= m;++i){
		int x1 = read() + 1,y1 = read() + 1,x2 = read() + 1,y2 = read() + 1;
		q[++cnt] = ques(x2,y2,i,1);
		q[++cnt] = ques(x1 - 1,y2,i,-1);
		q[++cnt] = ques(x2,y1 - 1,i,-1);
		q[++cnt] = ques(x1 - 1,y1 - 1,i,1);
	}
	sort(v + 1,v + n + 1,cmp1);
	sort(q + 1,q + cnt + 1,cmp2);
	int now = 1;
	for(int i = 1;i <= cnt;++i){
		while(v[now].x <= q[i].x && now <= n) 
			updata(v[now].y,1),now++;
		ans[q[i].id] += q[i].opt * query(q[i].y);
	//	printf("%d %d
",query(q[i].y),q[i].id);
	}
	for(int i = 1;i <= m;++i) printf("%d
",ans[i]);
	return 0;	
}
原文地址:https://www.cnblogs.com/wyxdrqc/p/10655228.html