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;
}

 

posted @ 2019-03-16 10:29  TLE自动机  阅读(194)  评论(0编辑  收藏  举报