原题链接
在无穷大的地图里,一只兔子以d跳跃距离可以上下左右到处跳,有n(<=1e5)个矩形的陷阱,求是否存在一个点(x,y)使得兔子从(x+0.5,y+0.5)开始跳跃,可以任意跳跃而不会跳到陷阱里。
分析:
取以(0,0)为左下角,(d,d)为右上角的矩形,再将其他陷阱矩形以空隔为d"平移"到该矩形内,问题就转化成能否在完成所有平移后的矩形里找到一个未被陷阱覆盖的大小为1*1的正方形,答案即是该正方形的左下角。
我们可以以类似扫描线一样的写法,以0到d-1的长度建立线段树,当前高度小于d,则说明存在该矩阵,再从子树里找到高度小于d的最终小区间,从而得到答案。
注意,在注意陷阱矩阵时,由于坐标可能是负的,所以不妨让所有坐标全部加上(int)1e9,最终将答案坐标减去(int)1e9即可。
注意,不能将坐标离散化,不然最终在子树中求最终小区间时,会得到离散化的坐标而不是真正的答案。
struct SegmentTree{
int l,r;
LL len,cnt;
SegmentTree(){
len=0,cnt=0;
}
}t[maxv*8];
struct A{
LL x,y1,y2;
int add;
};
vector<A> a;
bool cmp(A &a,A &b){
return a.x<b.x;
}
void pushUp(int p){t[p].len=(t[p].cnt>0)?t[p].r+1-t[p].l:t[p*2].len+t[p*2+1].len;}
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){
return;
}
int mid=l+r>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
}
void change(int p,int l,int r,int d){
if(l>r) return;
if(t[p].l>=l&&t[p].r<=r){
t[p].cnt+=d;
pushUp(p);
return;
}
int mid=t[p].l+t[p].r>>1;
if(l<=mid) change(p*2,l,r,d);
if(r>mid) change(p*2+1,l,r,d);
pushUp(p);
}
int main(){
int n,d,x1,x2,y1,y2,ansX=-1,ansY;
scanf("%d %d",&n,&d);
a.push_back({0,0,0,0});
for(int i=1;i<=n;i++){
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
#define xl x1
#define yl y1
#define xr x2
#define yr y2
xl += 1e9, yl += 1e9, xr += 1e9, yr += 1e9;
vector<pair<int,int> > xx,yy;
if (xl / d == xr / d) { //转移陷阱矩形
xl %= d, xr %= d;
xx.push_back({xl, xr});
} else if (xr - xl >= d) {
xx.push_back({0, d});
} else {
xl %= d, xr %= d;
xx.push_back({xl, d});
xx.push_back({0, xr});
}
if (yl / d == yr / d) {
yl %= d, yr %= d;
yy.push_back({yl, yr});
} else if (yr - yl >= d) {
yy.push_back({0, d});
} else {
yl %= d, yr %= d;
yy.push_back({yl, d});
yy.push_back({0, yr});
}
for(int i=0;i<xx.size();i++)
for(int j=0;j<yy.size();j++){
a.push_back({xx[i].first,yy[j].first,yy[j].second,1}),a.push_back({xx[i].second,yy[j].first,yy[j].second,-1});
}
}
sort(a.begin()+1,a.end(),cmp);
build(1,0,d-1);
change(1,a[1].y1,a[1].y2-1,a[1].add);
LL ans=0;
for(int i=2;i<a.size();i++){
if(a[i].x-a[i-1].x>0&&t[1].len>0&&t[1].len!=d){
ansX=a[i-1].x;
int cur=1;
while(1){ //在子树里求最终子区间
if(t[cur].l==t[cur].r){ansY=t[cur].l;break;}
cur*=2;
if(t[cur].len==t[cur].r+1-t[cur].l) cur++;
}
break;
}
change(1,a[i].y1,a[i].y2-1,a[i].add);
}
if(ansX!=-1) printf("YES\n%d %d",ansX-int(1e9),ansY-int(1e9));
else printf("NO");
return 0;
}