https://vjudge.net/problem/UVALive-3905
题目看着麻烦,其实写起来还好。
将每一个流星的运动分为X,Y方向上的运动,如果两个方向上都同时满足在范围之内,那么就是流星在方框内的时间范围。
扫描时间线的时候直接记录开始和结束的时间就可以了,每次不需要重新计算,而是维护结果就可以了,有点像点灯的题。实现的时候按照白书上的用结构体实现的,其实还可以开两个数组,分别储蓄开始和结束,sort之后类似于归并排序去处理。
#include <iostream>
#include<stdio.h>
#include<cstring>
#include<map>
#include<string.h>
#include<algorithm>
using namespace std;
struct Event
{
int type;
double time;
}event[100050*2];
void check(int x,int a,int w,double &L,double &R)
{
if(a==0)
{
if(x<w&&x>0) return;
else R=L-1;
}
else if(a>0)
{
L=max(L,-(double)x/a);
R=min(R,(double)(w-x)/a);
}
else
{
a*=-1;
L=max(L,(double)(x-w)/a);
R=min(R,(double)x/a);
}
}
bool cmp(Event a,Event b)
{
if(a.time==b.time)
return a.type>b.type;
else
return a.time<b.time;
}
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
int w,h,n,x,y,a,b,cnt=0;
scanf("%d%d%d",&w,&h,&n);
for(int i=0;i<n;i++)
{
scanf("%d%d%d%d",&x,&y,&a,&b);
double L=0,R=1e9;
check(x,a,w,L,R);
check(y,b,h,L,R);
if(L<R)
{
event[cnt++]=(Event){0,L};
event[cnt++]=(Event){1,R};
}
}
sort(event,event+cnt,cmp);
int ans=0,now=0;
for(int i=0;i<cnt;i++)
{
if(!event[i].type)
ans=max(ans,++now);
else
now--;
}
printf("%d\n",ans);
}
return 0;
}