二維數點問題
二維數點在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;
}