2021牛客多校6 H、Hopping Rabbit(扫描线)
原题意可以转化为把所有矩形映射到 \(0<=x<=d && 0<=y<=d\) 这个区域内,然后用扫描线判断有没有点没有矩形没有覆盖到,这个点为起点就可以存活。
首先把矩形映射下来是个非常难写的模拟:
vector<line>l;//扫描线的线段
void push(ll x, ll y, ll xx, ll yy)
{
if (xx - x > 0 && yy - y > 0)
{
l.push_back({ y,x,xx,1 });
l.push_back({ yy,x,xx,-1 });
}
}
cin >> n >> d;
for (int i = 1; i <= n; i++)
{
ll x, y, xx, yy;
cin >> x >> y >> xx >> yy;
ll dx = xx - x, dy = yy - y;//矩形的长和宽
Mod(x), Mod(y);//把矩形左下角先映射到扫描区域内
dx = min(dx, d);
dy = min(dy, d);//这两个超过d了也等价于他们等于d
xx = x + dx;//这是再加上长和宽推算出右上角的坐标
yy = y + dy;
//然后就是把在扫描区域外的面积映射回去
if (xx <= d && yy <= d)
push(x, y, xx, yy);
else if (xx > d && yy <= d)
{
push(x, y, d, yy);
push(0, y, xx - d, yy);
}
else if (yy > d && xx <= d)
{
push(x, y, xx, d);
push(x, 0, xx, yy - d);
}
else if (xx > d && yy > d)
{
push(x, y, d, d);
push(x, 0, d, yy - d);
push(0, y, xx - d, d);
push(0, 0, xx - d, yy - d);
}
}
把这个问题解决之后,就可以把扫描线的板子抄上去查询了:
void check(ll y)//把y从0到d扫描然后check
{
ll len = t[1].len;
if (len == d)return;//如果全部覆盖到了就直接return输出no
int p = 1, l = 1, r = d;//否则就去查询哪个点没覆盖到
while (t[p].len != 0)
{
//cout << l << " " << r << endl;
int mid = l + r >> 1;
int ok = mid - l + 1;//左区间全部覆盖到的长度
int len1 = t[p << 1].len;
int len2 = t[p << 1 | 1].len;
if (len1 < ok)//左边没覆盖到
{
p = p << 1;
r = mid;
}
else if (len2 < r - mid)
{
p = p << 1 | 1;
l = mid + 1;
}
}
cout << "YES" << endl;
cout << t[p].l - 1 << " " << y;
exit(0);
}
AC代码(比赛时由于手残导致赛后过题):
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define fastio ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define ll long long
#define ld long double
#define pii pair<int,int>
#define pll pair<ll,ll>
const int maxn = 1e6 + 10;
int N = 1e5 + 10;
int n;
ll d;
void Mod(ll& x)
{
x = ((x % d) + d) % d;
}
struct line {
ll y, x, xx, v;
friend bool operator<(line a, line b)
{
return a.y < b.y;
}
};
struct tree {
ll l, r;
ll cnt, len;
}t[maxn];
void pushup(int p)
{
ll l = t[p].l, r = t[p].r;
t[p].len = (t[p].cnt ? (r - l + 1) : (t[p << 1].len + t[p << 1 | 1].len));
}
void build(int l, int r, int p)
{
t[p].l = l, t[p].r = r;
t[p].cnt = 0, t[p].len = 0;
if (l == r)return;
int mid = l + r >> 1;
build(l, mid, p << 1);
build(mid + 1, r, p << 1 | 1);
}
void change(int x, int y, ll k, int p)
{
int l = t[p].l, r = t[p].r;
if (x <= l && r <= y)
{
t[p].cnt += k;
pushup(p);
return;
}
int mid = l + r >> 1;
if (x <= mid)change(x, y, k, p << 1);
if (y > mid)change(x, y, k, p << 1 | 1);
pushup(p);
}
vector<line>l;
void push(ll x, ll y, ll xx, ll yy)
{
if (xx - x > 0 && yy - y > 0)
{
l.push_back({ y,x,xx,1 });
l.push_back({ yy,x,xx,-1 });
}
}
void check(ll y)
{
ll len = t[1].len;
//cout << len << endl;
if (len == d)return;
int p = 1, l = 1, r = d;
while (t[p].len != 0)
{
//cout << l << " " << r << endl;
int mid = l + r >> 1;
int ok = mid - l + 1;
int len1 = t[p << 1].len;
int len2 = t[p << 1 | 1].len;
if (len1 < ok)
{
p = p << 1;
r = mid;
}
else if (len2 < r - mid)
{
p = p << 1 | 1;
l = mid + 1;
}
}
cout << "YES" << endl;
cout << t[p].l - 1 << " " << y;
exit(0);
}
int main()
{
/*
3 3
0 0 1 1
0 0 3 2
1 0 2 3
*/
//freopen("C:\\out.txt", "w", stdout);
fastio;
cin >> n >> d;
for (int i = 1; i <= n; i++)
{
ll x, y, xx, yy;
cin >> x >> y >> xx >> yy;
ll dx = xx - x, dy = yy - y;
Mod(x), Mod(y);
dx = min(dx, d);
dy = min(dy, d);
xx = x + dx;
yy = y + dy;
if (xx <= d && yy <= d)
push(x, y, xx, yy);
else if (xx > d && yy <= d)
{
push(x, y, d, yy);
push(0, y, xx - d, yy);
}
else if (yy > d && xx <= d)
{
push(x, y, xx, d);
push(x, 0, xx, yy - d);
}
else if (xx > d && yy > d)
{
push(x, y, d, d);
push(x, 0, d, yy - d);
push(0, y, xx - d, d);
push(0, 0, xx - d, yy - d);
}
}
sort(l.begin(), l.end());
build(1, d, 1);
int i = 0;
for (int y = 0; y < d; y++)
{
while (i < l.size() && l[i].y == y)
{
//cout << l[i].x << " " << l[i].xx<<" "<<l[i].v << endl;
change(l[i].x + 1, l[i].xx, l[i].v, 1);
i++;
}
check(y);
}
cout << "NO";
return 0;
}