UVALive 3905 Meteor (扫描线)
题目链接 https://vjudge.net/problem/UVALive-3905
第一次学到这个。对于每一颗流星,我们求出它在矩形框内待的时间段 L~R,把L和R按照不同的类型加入结构体。我们先按照时间从小到大排序,然后逐个扫描,遇到左端点L说明这个时刻流星已进入矩形框,个数加1,遇到右端点R个数减1,然后不断更新最大值。
最后要注意开始时间与结束事件重叠的情况,即当某个时刻开始时间与结束事件重叠。如果是先加后减的话,那么最大值会是2,相反先减后加答案就会是1。显然,在这里,后者才是正确的,因为由题意所有时间区间结尾开区间。
我认为求时间的区间这部分比较难以求解
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
struct node{
double t;
int type;//0表示右端点,1表示左端点
node(double _t = 0, int _type = 0) :t(_t), type(_type){};
bool operator<(const node &other) const{
if (t == other.t) return type < other.type;
return t < other.t;
}
}arr[N];
int ans,tot,w,h,n;
//解不等式 0< x + v*t <w
//
void update(int x, int v,int w, double &l, double &r)
{
if (v == 0)
{
if (x <= 0 || x >= w) r = l - 1;//这种情况肯定不会出现在矩形内部
}
else if (v>0) //-x< v*t < w-x ,这里v>0,两边同时除以v,方向不边
{
l = max(l, -1.0*x / v);
r = min(r, 1.0*(w - x) / v);
}
else//v<0,两边同时除v,方向改变
{
l = max(l, 1.0*(w - x) / v);
r = min(r, -1.0*x / v);
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
tot = 0;
ans = 0;
scanf("%d%d%d", &w, &h, &n);
for (int i = 0; i < n; i++)
{
int x, y, a, b;
scanf("%d%d%d%d", &x, &y, &a, &b);
double l = 0, r = INF;
update(x, a, w,l, r);
update(y, b, h,l, r);
if (r>l)
{
arr[tot++] = node(l, 1);
arr[tot++] = node(r, 0);
}
}
sort(arr, arr + tot);
int cnt = 0;
for (int i = 0; i < tot; i++)
{
if (arr[i].type) cnt++;
else cnt--;
ans = max(ans, cnt);
}
cout << ans << endl;
}
return 0;
}