P2163 [SHOI2007]園丁的煩惱(離線,樹狀數組二維數點)
題目鏈接:[傳送門](<https://www.luogu.org/problem/P2163)
輸入格式
第一行有兩個整數n,m(0≤n≤500000,1≤m≤500000)。n代表皇家花園的樹木的總數,m代表騎士們詢問的次數。
文件接下來的n行,每行都有兩個整數xi,yi,代表第i棵樹的座標(0≤xi,yi≤10000000)。
文件的最後m行,每行都有四個整數aj,bj,cj,dj,表示第j次詢問,其中所問的矩形以(aj,bj)爲左下座標,以(cj,dj)爲右上座標。
輸出格式
共輸出m行,每行一個整數,即回答國王以(aj,bj)和(cj,dj)爲界的矩形裏有多少棵樹
二維數點,很容易想到離線讓矩陣的點按x軸右端點從小到大排個序,依此添加新加入的點就好了。但是我們會發現樹狀數組每次統計的 不是y軸區間在x軸的範圍的點的個數,而是x軸範圍的個數。所以我們可以將矩形,分成矩陣點的個數減去矩形的點的個數就好了。也可以分成四個前綴矩形加減組合。(因爲當時直接想的就是前綴矩形,所以就分成了四個矩形了,不過都一樣啦
另外也可以cdq分治求,像二維偏序那樣
代碼:
#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
using namespace std;
typedef long long ll;
const int N=5e5+20;
const int inf=0x3f3f3f3f;
struct BitTree
{
int bt[N*4],MXN;
int lowbit(int k)
{
return k&-k;
}
void add(int k)
{
while(k<=MXN)
{
bt[k]+=1;
k+=lowbit(k);
}
}
int getpre(int k)
{
int ans=0;
while(k>0)
{
ans+=bt[k];
k-=lowbit(k);
}
return ans;
}
} ooo;
int xx[N],yy[N];
int a1[N],b1[N],a2[N],b2[N];
int ans[N][4];
vector<int> sx;
vector<int> sy;
struct pnode
{
int x,y;
bool operator < (const pnode &o) const
{
return x<o.x;
}
} pp[N];
struct qnode
{
int x,y,id,f;
qnode(){}
qnode(int x,int y,int id,int f):x(x),y(y),id(id),f(f){}
bool operator < (const qnode &o) const
{
return x<o.x;
}
} qt[N*4];
int getxid(int v)
{
return lower_bound(sx.begin(),sx.end(),v)-sx.begin()+1;
}
int getyid(int v)
{
return lower_bound(sy.begin(),sy.end(),v)-sy.begin()+1;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1; i<=n; ++i)
{
cin>>xx[i]>>yy[i];
sx.push_back(xx[i]);
sy.push_back(yy[i]);
}
for(int i=1; i<=m; ++i)
{
cin>>a1[i]>>b1[i]>>a2[i]>>b2[i];
sx.push_back(a1[i]);
sx.push_back(a2[i]);
sy.push_back(b1[i]);
sy.push_back(b2[i]);
}
sort(sx.begin(),sx.end());
sx.erase(unique(sx.begin(),sx.end()),sx.end());
sort(sy.begin(),sy.end());
sy.erase(unique(sy.begin(),sy.end()),sy.end());
for(int i=1;i<=n;++i) {
xx[i]=getxid(xx[i]);
yy[i]=getyid(yy[i]);
pp[i-1].x=xx[i];
pp[i-1].y=yy[i];
}
int top=0;
for(int i=1;i<=m;++i) {
a1[i]=getxid(a1[i]);
a2[i]=getxid(a2[i]);
b1[i]=getyid(b1[i]);
b2[i]=getyid(b2[i]);
qt[top++]=qnode(a2[i],b2[i],i,3);
qt[top++]=qnode(a1[i]-1,b1[i]-1,i,0);
qt[top++]=qnode(a2[i],b1[i]-1,i,1);
qt[top++]=qnode(a1[i]-1,b2[i],i,2);
}
sort(qt,qt+top);
sort(pp,pp+n);
ooo.MXN=sy.size();
int p=0;//待選位置
for(int i=0;i<top;++i)
{
while(p < n&& pp[p].x<=qt[i].x){
ooo.add(pp[p].y);
++p;
}
ans[qt[i].id][qt[i].f]=ooo.getpre(qt[i].y);
}
for(int i=1;i<=m;++i){
cout<<ans[i][3]+ans[i][0]-ans[i][1]-ans[i][2]<<endl;;
}
return 0;
}