二維數點問題


二維數點問題

二維數點在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\n",query(q[i].y),q[i].id);
	}
	for(int i = 1;i <= m;++i) printf("%d\n",ans[i]);
	return 0;	
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM