题目大意:今晚有流星划过,求在某瞬间最多有多少流星能被拍进镜头?
分析:咋看之下有点复杂。一点点分析后,可以发现这题是借助扫描线来解决,类似区间并,面积并。
每个流星可以看做一个开区间,这个问题可以转化为,求扫描线在哪个位置时与最多的开区间相交。
首先,我们需要将流星转化为开区间,如何转化呢?题目给的数据有坐标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; }