假设从光源$(0,0)$射出的一束光第一次碰到右边墙上的$(x,y)$,那么第$k$次的坐标是$(kx,ky)$。
如果在第$k$次到达了左边某个点且$k$是$2^d imes o$的形式,其中$o$是奇数,那么在第$2^d$次一定也能到达这个点。
枚举所有不超过最大坐标两倍的$2^d$,判断左边每个窗户在$2^d$次能否被照亮。
那么右边要存在一个矩形覆盖$(frac{x}{2^d-1},frac{y}{2^d-1})$,左边要存在一个矩形覆盖$(frac{x}{2^d-2},frac{y}{2^d-2})$,右边要存在一个矩形覆盖$(frac{x}{2^d-3},frac{y}{2^d-3})$,左边要存在一个矩形覆盖$(frac{x}{2^d-4},frac{y}{2^d-4})$...
把每个矩形缩放成$O(2^d)$份,并把左右两面墙合并,那么如果左边某个矩形内部存在一个至少被$2^d$个矩形覆盖的点则可行,注意这里可以用分数类做到全整数计算。
扫描线+线段树维护扫描线上每个区间内被覆盖次数的最大值,同时将每个左边的矩形拆成线段树上$O(log n)$条线段放入。
每次处理完修改操作后,从线段树根节点开始遍历,如果区间最大值$<2^d$或者当前子树内没有任何线段则return,这样即可在总计$O(nlog n)$的时间里找出所有被照亮的矩形。
时间复杂度$O(nwlog n)$,其中$w$为坐标范围。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=605,M=4200005,MX=1025; int n,m,K,i,ans[N],fin,cy,ce,_,f[MX],C,D,P,pl[N<<1][MX],pr[N<<1][MX]; int py[1400000],l[N<<1][MX],r[N<<1][MX],del[N],cur; bool has[M];int tag[M],val[M],g[M],v[30005],nxt[30005],ed; struct Rect{int x1,y1,x2,y2;}a[N],b[N]; struct E{int x,t;E(){}E(int _x,int _t){x=_x,t=_t;}}e[1400000]; inline int sgn(int a,int b){ int t=(a>>11)*(b&2047)-(b>>11)*(a&2047); if(!t)return 0; return t<0?-1:1; } inline bool cmpf(int a,int b){return sgn(a,b)<0;} inline bool cmpe(const E&a,const E&b){return sgn(a.x,b.x)<0;} inline void addrect(const Rect&a,int b,int x){ l[x][b]=py[++cy]=a.y1<<11|b; r[x][b]=py[++cy]=a.y2<<11|b; e[++ce]=E(a.x1<<11|b,x<<11|b); e[++ce]=E(a.x2<<11|b,(-x)<<11|b); } inline int lower(int x){ int l=1,r=cy,mid; while(1){ if(!sgn(x,py[mid=(l+r)>>1]))return mid; if(sgn(x,py[mid])<0)r=mid-1;else l=mid+1; } } void change(int x,int a,int b){ if(C<=a&&b<=D){tag[x]+=P;val[x]+=P;return;} int mid=(a+b)>>1; if(C<=mid)change(x<<1,a,mid); if(D>mid)change(x<<1|1,mid+1,b); val[x]=max(val[x<<1],val[x<<1|1])+tag[x]; } void ins(int x,int a,int b){ has[x]=1; if(C<=a&&b<=D){v[++ed]=P;nxt[ed]=g[x];g[x]=ed;return;} int mid=(a+b)>>1; if(C<=mid)ins(x<<1,a,mid); if(D>mid)ins(x<<1|1,mid+1,b); } void dfs(int x,int a,int b,int t){ if(!has[x]||val[x]+t<K)return; for(int i=g[x];i;i=nxt[i])if(sgn(del[v[i]],cur)>0)ans[v[i]]=1; g[x]=0; if(a==b){has[x]=0;return;} int mid=(a+b)>>1; t+=tag[x]; dfs(x<<1,a,mid,t),dfs(x<<1|1,mid+1,b,t); has[x]=has[x<<1]|has[x<<1|1]; } void solve(int _K){ int i,j,o,x,y; K=_K; for(i=1;i<=n;i++)if(!ans[i]&&f[a[i].y2]>=K)break; if(i>n)return; ce=cy=0; for(i=1;i<=n;i++){ for(j=K;j>0;j-=2){ if(j<K&&!ans[i])break; addrect(a[i],j,i); } if(!ans[i])del[i]=a[i].x2<<11|K; } for(i=1;i<=m;i++)for(j=K-1;j>0;j-=2)addrect(b[i],j,i+n); sort(py+1,py+cy+1,cmpf); for(_=0,i=1;i<=cy;i++)if(i==1||sgn(py[_],py[i]))py[++_]=py[i]; cy=_--; for(i=1;i<=n;i++)for(j=K;j>0;j-=2){ if(j<K&&!ans[i])break; pl[i][j]=lower(l[i][j]),pr[i][j]=lower(r[i][j])-1; } for(i=n+1;i<=n+m;i++)for(j=K-1;j>0;j-=2)pl[i][j]=lower(l[i][j]),pr[i][j]=lower(r[i][j])-1; sort(e+1,e+ce+1,cmpe); ed=0; for(j=1;j<=_;j<<=1);j<<=1; memset(tag,0,j*sizeof(int)); memset(val,0,j*sizeof(int)); memset(g,0,j*sizeof(int)); memset(has,0,j*sizeof(bool)); for(i=1;i<=ce;i=j){ cur=e[i].x; for(j=i;j<=ce&&!sgn(cur,e[j].x);j++){ o=e[j].t; x=o>>11; y=o&2047; if(o>0)o=1;else x=-x,o=-1; C=pl[x][y],D=pr[x][y],P=o; change(1,1,_); if(x<=n&&o==1&&!ans[x]&&y==K)P=x,ins(1,1,_); } dfs(1,1,_,0); } } int main(){ for(f[1]=i=2;i<MX;i++)f[i]=f[i>>1]<<1; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2); for(i=1;i<=m;i++)scanf("%d%d%d%d",&b[i].x1,&b[i].y1,&b[i].x2,&b[i].y2); for(i=2;i<MX;i<<=1)solve(i); for(i=1;i<=n;i++)if(ans[i])fin++; printf("%d ",fin); for(i=1;i<=n;i++)if(ans[i])printf("%d ",i); return 0; }