题解:
用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;
}
}