【计几】cf1359F(edu88)RC Kaboom Show

题目链接:http://codeforces.com/contest/1359/problem/F

题意:给你25000个点,每个点有各自的方向以及速度,问最少需要多少时间使得发生碰撞(两点同一位置),注意点的出发时间任选。

做法:很容易想到,三分时间,然后判断n条线段是否存在交点,然后我就不会了。

看了别人的代码发现,用set维护线段相对位置,这像极了我之前的一道题(https://www.cnblogs.com/xiaobuxie/p/12642374.html第十题)

首先定义两个线段的大小关系:在下方的线段是小的,如果两个线段相交,就以交点左边,下方的线段为小。

然后画图可以发现这个大小关系是可以传递的,所以我们可以用set来维护这个东西。之前那题是极角的扫描线,这题则是竖直的扫描线。

然后我们把线段的端点排个序,按照左端点插入线段,右端点删除线段那样维护这个set,然后我们可以发现,两个线段s1 和 s2 相交的话,假设s1 > s2 有两种情况:

第一种情况:set里面s1 和 s2 是相邻的,那么我们只需要在插入每个线段的时候,判断它 和它相邻的线段 是否相交即可。

第二种情况:set里面 s1 和 s2 不相邻,也就是说有某些线段卡在s1和s2中间,这些线段中假如 a 和s1相交的,那么 s2 = max(s2,a ) , 假如和 s2 相交, s1 = min(s1,a),也就是说我们肯定能找到相交的两个线段 s1和s2,使得不存在 s1 到s2 之间的线段和 s1或者s2相交。

然后我们可以发现这些线段会卡在 s1 和 s2 以及 s1s2的交点 所形成的区间内, 那么对于这些线段中最后删除的一个线段,寻找它的pre 和 nex (也就是s2 和 s1 ) ,判断相交即可。

坑点:用long double 。。。。上一题set也是用long double 才能过,然后注意精度。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N = 25000+9;
  4 #define eps 1e-10
  5 #define ld long double
  6 int sgn(ld x){
  7     if( fabs(x) < eps ) return 0;
  8     if(x<0) return -1;
  9     return 1;
 10 }
 11 struct Point{
 12     ld x,y;
 13     Point operator + (const Point& b)const{
 14         return (Point){x+b.x,y+b.y};
 15     }
 16     Point operator - (const Point& b)const{
 17         return (Point){x-b.x,y-b.y};
 18     }
 19     Point operator * (const ld& b)const{
 20         return (Point){x*b,y*b};
 21     }
 22     Point operator / (const ld& b)const{
 23         return (Point){x/b,y/b};
 24     }
 25     ld len(){
 26         return sqrt(x*x+y*y);
 27     }
 28     bool operator <(const Point& b)const{
 29         if( x==b.x ) return x < b.y;
 30         return x < b.x;
 31     }
 32     bool operator == (const Point& b)const{
 33         return x==b.x && y==b.y;
 34     }
 35 }p[N],dir[N];
 36 struct Seg{
 37     Point s,t;
 38     ld gety(ld x)const{
 39         if( fabs(t.x-s.x ) < eps ) return t.y;
 40         return s.y + (t.y-s.y) * (x-s.x)/(t.x-s.x);
 41     }
 42     
 43 }seg[N];
 44 set<Seg> sgs;
 45 bool operator < ( const Seg& a,const Seg& b){
 46     ld xp = max(a.s.x,b.s.x);
 47     ld ya = a.gety(xp) , yb = b.gety(xp);
 48     if(fabs(ya-yb)<eps){
 49         if( fabs(a.s.x-b.s.x)<eps ) return a.t.x<b.t.x-eps;
 50         return a.s.x<b.s.x-eps;
 51     }
 52     return ya < yb;
 53 }
 54 ld speed[N];
 55 int n;
 56 ld cross(Point a,Point b){
 57     return a.x*b.y - b.x*a.y;
 58 }
 59 //两线段是否相交
 60 bool insert(Seg l1,Seg l2){
 61     return
 62         max(l1.s.x,l1.t.x) >= min(l2.s.x,l2.t.x) &&
 63         max(l2.s.x,l2.t.x) >= min(l1.s.x,l1.t.x) &&
 64         max(l1.s.y,l1.t.y) >= min(l2.s.y,l2.t.y) &&
 65         max(l2.s.y,l2.t.y) >= min(l1.s.y,l1.t.y) &&
 66         sgn( cross( l2.s-l1.s,l1.t-l1.s) ) * sgn( cross( l2.t-l1.s,l1.t-l1.s) )<=0 &&
 67         sgn( cross( l1.s-l2.s,l2.t-l2.s) ) * sgn( cross( l1.t-l2.s,l2.t-l2.s) )<=0;
 68 }
 69 bool pre(set<Seg>::iterator it,set<Seg>::iterator& res){    
 70     if(it == sgs.begin()) return 0;
 71     res = --it;
 72     return 1;
 73 }
 74 bool nex(set<Seg>::iterator it,set<Seg>::iterator& res){
 75     res = ++it;
 76     if( res == sgs.end() ) return 0;
 77     return 1;    
 78 }
 79 bool judge(double tim){
 80     vector< pair<Point,int> > pts;
 81     for(int i = 1;i<=n;++i){
 82         seg[i].s = p[i];
 83         seg[i].t = p[i] + dir[i] * speed[i] * tim/dir[i].len();
 84         if(seg[i].t < seg[i].s ) swap(seg[i].s,seg[i].t);
 85         pts.push_back({seg[i].s,i});
 86         pts.push_back({seg[i].t,-i});
 87     }
 88     sort(pts.begin(),pts.end());
 89     sgs.clear();
 90     for(int i = 0;i<pts.size();++i){
 91         int id = pts[i].second;
 92         
 93         if(id>0){
 94             sgs.insert(seg[id]);
 95             set<Seg>::iterator it = sgs.lower_bound(seg[id]);
 96             
 97             set<Seg>::iterator tem;
 98             if(pre(it,tem)){
 99                 if(insert(seg[id],(*tem))){
100                     return 1;
101                 }
102             }
103             if(nex(it,tem)){
104                 if( insert(seg[id],(*tem))) return 1;
105             }
106         }
107         else{
108             id = -id;
109             set<Seg>::iterator it = sgs.lower_bound(seg[id]);
110             set<Seg>::iterator le , ri;
111             if( pre(it,le) && nex(it,ri) ){
112                 if( insert((*le),(*ri) ) )return 1;
113             }
114             sgs.erase(it);
115         }
116     }
117     return 0;
118 }
119 int main(){
120     cout << setprecision(10) << fixed;
121     cin>>n;
122     for(int i = 1;i<=n;++i){
123         cin>>p[i].x>>p[i].y>>dir[i].x>>dir[i].y>>speed[i];
124     }
125     ld l = 0, r = 1e12,res = -1;
126     for(int cas = 1;cas<=60;++cas){
127         ld m = (l+r)/2;
128         if(judge(m)){
129             res = m;
130             r = m;
131         }
132         else l = m;
133     }
134     if(res == -1) puts("No show :(");
135     else cout<<res<<endl;
136 }
View Code

 

posted @ 2020-05-29 19:06  小布鞋  阅读(406)  评论(0编辑  收藏  举报