P3194 [HNOI2008]水平可見直線 題解
阿新 • • 發佈:2021-08-04
光看是解不出題的。
自(he) 己(wan)畫(ti)圖(jie),發現沒被擋住的多條直線會在平面上形成一個下凸包,從左到右斜率遞增。
(取自p_b_p_b題解)
於是,我們將直線以斜率為第一關鍵字,截距為第二關鍵字從大到小排序;
然後從前往後列舉直線,加入單調棧。
當單調棧內直線數量 \(\ge\) 2時,設 \(l_1\) 與 \(l_2\) 為棧頂兩直線,\(L\) 為列舉直線,用一元二次方程算出 \(L\) 與 \(l_1\) , \(l_1\) 與 \(l_2\) 的交點橫座標 \(x_1\),\(x_2\) 。若 \(x_2>x_1\) ,則 \(l_1\) 已經被覆蓋,退棧,重複該操作到 \(x_2<x_1\)
#include <bits/stdc++.h> #define ll long long #define rgi register int using namespace std; const int M=5e4+7; inline int read(){ int w=0,r=1;char c=getchar(); while(!(isdigit(c)||c=='0'))c=getchar(); if(c=='-')r=-1,c=getchar(); while(isdigit(c))w=w*10+c-'0',c=getchar(); return w*r; } int n,m,stk[M],ans[M],cnt;double a,b,r; struct l{ int ii;double k,b; }p[M]; bool cmp(l aa,l bb){ return aa.k>bb.k||(aa.k==bb.k&&aa.b>bb.b); } double xx(int aa,int bb){ return (double)(p[bb].b-p[aa].b)/(p[aa].k-p[bb].k); } int main(){ n=read(); for(int i=1;i<=n;i++){ scanf("%lf%lf",&p[i].k,&p[i].b); p[i].ii=i; } sort(p+1,p+n+1,cmp); for(int i=1;i<=n;i++){ if(p[i].k==p[stk[cnt]].k&&i>1)continue; while(cnt>=2&&xx(stk[cnt-1],stk[cnt])<=xx(stk[cnt],i))cnt--; stk[++cnt]=i; ans[cnt]=p[i].ii; } sort(ans+1,ans+cnt+1); for(int i=1;i<=cnt;i++)printf("%d ",ans[i]); printf("\n"); return 0; } /* 3 -1 0 1 0 0 0 */