假设从光源$(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;
}