BJ模拟:Rectangle Query(bitset)

传送门

题解:
用bitset+分块求点集交。
去重类似记pre,以横坐标为例,如果两个点横坐标相同且会同时被计算,那么我们保证只统计下面的点即可。为了保证这一点我们把这个点复制一份到新图的下面的点的位置上去,然后再求一次点集交即可统计有多少被算重。

时间复杂度: O(nn+nq64) O ( n n + n q 64 )

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;

const int RLEN=1<<18|1;
inline char nc() {
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
    char ch=nc(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
    return i*f;
}
inline void W(int x) {
    static int buf[50];
    if(!x) {putchar('0'); return;}
    if(x<0) {putchar('-'); x=-x;}
    while(x) {buf[++buf[0]]=x%10; x/=10;}
    while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}

const int N=5e4+50, B=230;
int type,n,nX,nY,BL,lstX,lstY;
struct BITSET {
    ULL *a;
    BITSET() { a=new ULL[BL](); }
    ~BITSET() {delete a;}
    inline void operator =(const BITSET &b) {for(int i=0;i<BL;i++) a[i]=b.a[i];}
    inline void operator |=(const BITSET &b) {for(int i=0;i<BL;i++) a[i]|=b.a[i];}
    inline void operator &=(const BITSET &b) {for(int i=0;i<BL;i++) a[i]&=b.a[i];}
    inline void operator ^=(const BITSET &b) {for(int i=0;i<BL;i++) a[i]^=b.a[i];}
    inline void set(int pos) {a[pos/64]|=(1ull<<(pos%64));}
    inline int count(int rs=0) {for(int i=0;i<BL;i++) rs+=__builtin_popcountll(a[i]); return rs;}
};
struct P {   
    int x,y,id;
    P(int x=0,int y=0,int id=0):x(x),y(y),id(id){}
} p[N], pX[N], pY[N], rp[N], rpX[N], rpY[N];
inline bool cmpx(const P &a,const P &b) {return a.x<b.x || (a.x==b.x && a.y<b.y) || (a.x==b.x && a.y==b.y && a.id<b.id);}
inline bool cmpy(const P &a,const P &b) {return a.y<b.y || (a.y==b.y && a.x<b.x) || (a.x==b.x && a.y==b.y && a.id<b.id);}

struct Block {
    int nn,S; P *X, *Y;
    BITSET *Xc[B],*Yc[B];
    inline void init(P *Xx,P *Yy,int tot) {
        if(!tot) return;
        nn=tot; X=Xx, Y=Yy; S=sqrt(nn);
        memcpy(Y+1,X+1,sizeof(P)*nn);
        sort(X+1,X+nn+1,cmpx);
        sort(Y+1,Y+nn+1,cmpy);
        for(int i=1;i<=nn;i++) if(Xc[i/S]==NULL) Xc[i/S]=new BITSET, Yc[i/S]=new BITSET;
        for(int i=1;i<=nn;i++) {
            if(!(i%S)) *Xc[i/S]|=*Xc[i/S-1], *Yc[i/S]|=*Yc[i/S-1];
            Xc[i/S]->set(X[i].id); Yc[i/S]->set(Y[i].id);
        }
    }
    inline BITSET* get(int l,int r,BITSET *const*BT,const P *pi) const {
        BITSET *tp=new BITSET;
        if(!nn) return tp;
        int L=l/S+1, R=r/S-1;
        if(R>=L-1) {
            if(R>=0) *tp=*BT[R];
            if(L-1>=0) *tp^=*BT[L-1];
            L=S*L, R=S*(R+1);
            for(int i=l;i<L;i++) tp->set(pi[i].id);
            for(int i=R;i<=r;i++) tp->set(pi[i].id);
        } else {
            for(int i=l;i<=r;i++) tp->set(pi[i].id);
        }
        return tp;
    }
    inline BITSET* get(int xc1,int xc2,int yc1,int yc2) const {
        if(!nn) {BITSET *tp=new BITSET; return tp;}
        int l1=lower_bound(X+1,X+nn+1,P(xc1,-2e9,0),cmpx)-X;
        int r1=lower_bound(X+1,X+nn+1,P(xc2,2e9,0),cmpx)-X-1;
        int l2=lower_bound(Y+1,Y+nn+1,P(-2e9,yc1,0),cmpy)-Y;
        int r2=lower_bound(Y+1,Y+nn+1,P(2e9,yc2,0),cmpy)-Y-1;
        BITSET *t1=get(l1,r1,Xc,X), *t2=get(l2,r2,Yc,Y);
        *t1&=*t2; delete t2; return t1;
    }
} ori,newX,newY;

int main() {
    type=rd(), n=rd(), BL=n/64+3;
    for(int i=1;i<=n;i++) p[i].x=rd(), p[i].y=rd(), p[i].id=i;
    sort(p+1,p+n+1,cmpx);
    for(int i=1;i<=n;i++) if(i>1 && p[i].x==p[i-1].x) pY[++nY]=P(p[i].x,p[i-1].y,p[i].id);
    sort(p+1,p+n+1,cmpy);
    for(int i=1;i<=n;i++) if(i>1 && p[i].y==p[i-1].y) pX[++nX]=P(p[i-1].x,p[i].y,p[i].id);

    ori.init(p,rp,n); newX.init(pX,rpX,nX); newY.init(pY,rpY,nY);

    for(int q=rd();q;q--) {
        int det=(lstX+lstY)*type, xc1=rd()+det, yc1=rd()+det, xc2=rd()+det, yc2=rd()+det;
        BITSET *t1=ori.get(xc1,xc2,yc1,yc2), *t2=newX.get(xc1,xc2,yc1,yc2), *t3=newY.get(xc1,xc2,yc1,yc2);
        *t2&=*t1; *t3&=*t1;
        lstX=t1->count(); lstY=lstX-t2->count(); lstX=lstX-t3->count();
        W(lstX); putchar(' '); W(lstY); putchar('\n');
        delete t1; delete t2; delete t3;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值