Uva1398--Meteor(扫描线)

来源:互联网 发布:linux mysql配置文件 编辑:程序博客网 时间:2024/05/29 10:37

题目大意:今晚有流星划过,求在某瞬间最多有多少流星能被拍进镜头?


分析:咋看之下有点复杂。一点点分析后,可以发现这题是借助扫描线来解决,类似区间并,面积并。

每个流星可以看做一个开区间,这个问题可以转化为,求扫描线在哪个位置时与最多的开区间相交。

首先,我们需要将流星转化为开区间,如何转化呢?题目给的数据有坐标x,y,以及xy方向上的速度,那么我们很自然地想到分解成xy两个方向上来求区间,然后得到的两个区间的相交部分,就是该流星的开区间。

然后,就可以用扫描线啦~


需要注意的是,当某一位置既有前一个区间的右端点,又有后一个区间的左端点时,我们先操作右端点,再操作左端点。很好理解,因为在镜头边缘的点,我们并不计数。



代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 111111;struct Event {    int x;    int type;    bool operator < (const Event & cmp) {        return x < cmp.x || (x == cmp.x && type > cmp.type);    }}e[2*maxn];void update(int a, int x, int w, int& L, int& R) {    if(a == 0) {        if(x <= 0|| x >= w) R = L-1;    }    else if(a > 0) {        L = max(L, -x*2520/a);        R = min(R, (w-x)*2520/a);    }    else {        L = max(L, (w-x)*2520/a);        R = min(R, -x*2520/a);    }}int main() {    int T;    scanf("%d", &T);    while(T--) {        int n, w, h;        int a, b, x, y;        scanf("%d%d%d", &w, &h, &n);        int cnt = 0;        for(int i = 0; i < n; i++) {            scanf("%d%d%d%d", &x, &y, &a, &b);            int L = 0, R = 1 << 30;            update(a, x, w, L, R);            update(b, y, h, L, R);            if(R > L) {                e[cnt++] = (Event){L, 0};                e[cnt++] = (Event){R, 1};            }        }        sort(e, e+cnt);        int ans = 0;        int tt = 0;        for(int i = 0; i < cnt; i++) {            if(e[i].type == 0) {                tt++;                ans = max(ans, tt);            }            else tt--;        }        printf("%d\n", ans);    }    return 0;}


0 0
原创粉丝点击