P2163 [SHOI2007]園丁的煩惱(離線,樹狀數組二維數點)

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軸區間[y1,y2][y1,y2]在x軸的[x1,x2][x1,x2]範圍的點的個數,而是x軸[0,x2][0,x2]範圍的個數。所以我們可以將矩形x[x1,x2],y[y1,y2]x\in[x1,x2],y\in[y1,y2],分成矩陣x[0,x2],y(y1,y2)x\in[0,x2],y\in(y1,y2)點的個數減去矩形x[0,x11],y[y1,y2]x\in[0,x1-1],y\in[y1,y2]的點的個數就好了。也可以分成四個前綴矩形加減組合。(因爲當時直接想的就是前綴矩形,所以就分成了四個矩形了,不過都一樣啦

另外也可以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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章