H-Hopping Rabbit
思路
其实从 ( x , y ) (x, y) (x,y) 点出发和从 ( x + d , y + d ) (x + d, y + d) (x+d,y+d) 出发是一样的,因为左右都只能跳 d d d 的距离,那么有区别的出发点其实都可以归纳到 x ∈ [ 0 , d ) , y ∈ [ 0 , d ) x \in [0, d), y \in [0, d) x∈[0,d),y∈[0,d) 的范围内。我们把所有的陷阱都通过这种方法映射到 x ∈ [ 0 , d ) , y ∈ [ 0 , d ) x \in [0, d), y \in [0, d) x∈[0,d),y∈[0,d) 的范围内(赋值为1),然后找任意一个值为0的点输出其坐标即可,若没有这样的点就是不可行。
听起来很简单,但是d的范围1e5,暴力显然不行。开始觉得用二维线段树也可以做,奈何不会,后来在想“什么数据结构可以用来处理矩形覆盖问题”的时候,突然想到扫描线。扫描线扫的过程中查找是不是有某一列的值不是满的,若有就说明该列有0,若无则没有答案。若找到了某个有0的列,就将其之前的所有线段开头结尾在一个初始为0的数组中标记(开头+1,结尾-1),最后 O ( n ) O(n) O(n) 求一遍前缀和就可以知道在修改到该列时,整列的状态,此时若有前缀和为0的位置,就是我们要找的答案。这样的复杂度是 O ( log d + d ) O(\log d + d) O(logd+d) ,是可以通过的。
不过好像题目数据有点弱,我们漏判了开头到第一个矩形的部分,居然过了。
代码
赛后自己重新写了一遍,完美复现了赛场上的所有错误(不是)
被负数取模坑了几个小时,好像这个细节还是我在赛场上提出来的,转头就忘不愧是我()
容易出错的地方:输入的坐标可能是负数,要处理成正数再取模;离散化处理y轴坐标时,如果是矩阵在 [ 0 , d ) [0, d) [0,d) 中的映射不连续(即取模后 x 1 > x 2 o r y 1 > y 2 x_1 > x_2 \ or \ y_1 > y_2 x1>x2 or y1>y2 的情况),要记得多添加0和d两个y轴坐标。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n;
struct Segment
{
ll x, y1, y2;
int k;
bool operator < (const Segment& t) const
{
return x < t.x;
}
} seg[N * 8];
struct node
{
int l, r;
ll cnt;
ll len;
} tr[N * 16];
vector<int> ys;
int find(int y)
{
return lower_bound(ys.begin(), ys.end(), y) - ys.begin();
}
void pushup(int u)
{
if(tr[u].cnt)
tr[u].len = ys[tr[u].r + 1] - ys[tr[u].l];
else if(tr[u].l != tr[u].r)
tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;
else
tr[u].len = 0;
}
void build(int u, int l, int r)
{
tr[u] = {l, r, 0, 0};
if(l != r)
{
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
}
}
void modify(int u, int l, int r, int k)
{
if(tr[u].l >= l && tr[u].r <= r)
{
tr[u].cnt += k;
pushup(u);
}
else
{
int mid = (tr[u].l + tr[u].r) >> 1;
if(l <= mid)
modify(u << 1, l, r, k);
if(r > mid)
modify(u << 1 | 1, l, r, k);
pushup(u);
}
}
int f[N];
int main()
{
int n, d, j = 0;
scanf("%d%d", &n, &d);
bool flag = 0;
seg[j++] = {0, 0, d, 0};
seg[j++] = {d, 0, d, 0};
ll add = 1e9 * d;
for(int i = 0; i < n; i++)
{
ll x1, y1, x2, y2;
scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
if(x2 - x1 >= d && y2 - y1 >= d)
{
flag = 1;
break;
}
x1 += add;
x2 += add;
y1 += add;
y2 += add;
x1 %= d;
y1 %= d;
x2 = (x2 - 1 + d) % d + 1;
y2 = (y2 - 1 + d) % d + 1;
if(x1 < x2)
{
if(y1 < y2)
{
seg[j++] = {x1, y1, y2, 1};
seg[j++] = {x2, y1, y2, -1};
ys.push_back(y1);
ys.push_back(y2);
}
else if(y1 > y2) // [y1, d) + [0, y2)
{
seg[j++] = {x1, y1, d, 1};
seg[j++] = {x2, y1, d, -1};
seg[j++] = {x1, 0, y2, 1};
seg[j++] = {x2, 0, y2, -1};
ys.push_back(y1);
ys.push_back(y2);
ys.push_back(0);
ys.push_back(d);
}
else
{
seg[j++] = {x1, 0, d, 1};
seg[j++] = {x2, 0, d, -1};
ys.push_back(0);
ys.push_back(d);
}
}
else if(x1 > x2)
{
if(y1 < y2) // [x1, d) + [0, x2)
{
seg[j++] = {x1, y1, y2, 1};
seg[j++] = {d, y1, y2, -1};
seg[j++] = {0, y1, y2, 1};
seg[j++] = {x2, y1, y2, -1};
ys.push_back(y1);
ys.push_back(y2);
}
else if(y1 > y2) // [x1, d) + [0, x2) + [y1, d) + [0, y2)
{
seg[j++] = {x1, y1, d, 1};
seg[j++] = {d, y1, d, -1};
seg[j++] = {0, y1, d, 1};
seg[j++] = {x2, y1, d, -1};
seg[j++] = {x1, 0, y2, 1};
seg[j++] = {d, 0, y2, -1};
seg[j++] = {0, 0, y2, 1};
seg[j++] = {x2, 0, y2, -1};
ys.push_back(y1);
ys.push_back(y2);
ys.push_back(0);
ys.push_back(d);
}
else
{
seg[j++] = {x1, 0, d, 1};
seg[j++] = {d, 0, d, -1};
seg[j++] = {0, 0, d, 1};
seg[j++] = {x2, 0, d, -1};
ys.push_back(0);
ys.push_back(d);
}
}
else
{
if(y1 < y2)
{
seg[j++] = {0, y1, y2, 1};
seg[j++] = {d, y1, y2, -1};
ys.push_back(y1);
ys.push_back(y2);
}
else if(y1 > y2) // [y1, d) + [0, y2)
{
seg[j++] = {0, y1, d, 1};
seg[j++] = {d, y1, d, -1};
seg[j++] = {0, 0, y2, 1};
seg[j++] = {d, 0, y2, -1};
ys.push_back(y1);
ys.push_back(y2);
ys.push_back(0);
ys.push_back(d);
}
else
{
flag = 1;
break;
}
}
}
if(flag)
{
printf("NO\n");
return 0;
}
int cnt = j;
sort(seg, seg + cnt);
sort(ys.begin(), ys.end());
ys.erase(unique(ys.begin(), ys.end()), ys.end());
build(1, 0, ys.size() - 2);
int res = 0;
int pos = -1;
for(int i = 0; i < cnt; i++)
{
if(i > 0)
{
int h = seg[i].x - seg[i - 1].x;
int w = tr[1].len;
if(h && w < d)
{
pos = i;
break;
}
if(seg[i].k)
modify(1, find(seg[i].y1), find(seg[i].y2) - 1, seg[i].k);
}
}
if(pos == -1)
{
printf("NO\n");
return 0;
}
for(int i = 0; i < pos; i++)
{
f[seg[i].y1] += seg[i].k;
f[seg[i].y2] -= seg[i].k;
}
int y = -1;
for(int i = 0; i < d; i++)
{
if(i > 0)
f[i] = f[i - 1] + f[i];
if(f[i] == 0)
{
y = i;
break;
}
}
if(y == -1)
{
printf("NO\n");
return 0;
}
int x = seg[pos - 1].x;
printf("YES\n%d %d\n", x, y);
return 0;
}