傳送門
這道題我自己想了想……不過並沒有想出什麼很好的方法。
我們簡單一點考慮,問題可以轉化成求所有在最上面的直線的那個集合中有哪些直線。我們知道斜率最大(接近正無窮)和斜率最小(接近負無窮)的是肯定要被保留下來的,而且還是在最兩側的兩條直線。
那麼對於一般的直線,我們考慮一下。
如上圖,這兩條直線都是可見的。那麼再插入一條新的直線,就會變成這個樣子:
這樣的話,可以發現對於斜率更大的一條線,如果他與當前斜率最大的線的交點在斜率最大和次大的直線交點的左側,那麼當前斜率最大的直線會被覆蓋,我們應該使用新的直線去代替這條直線,而如果是在右側,那麼我們就把它保留下來即可。
這樣似乎思路就很清晰了。我們把直線按照斜率從小到大排序(當然反過來也一樣),之後使用單調棧來維護當前可以被看見的直線有哪些,每次遇到一條新的,斜率更大的直線,我們把它和棧頂元素的交點計算出來,再把棧頂元素和棧中第二個元素的交點計算出來,之後按照上面的方法處理單調棧就好。
然後,對於有多條直線斜率相同的情況,肯定是去取截距最大的那一條(下面的一定被它覆蓋了),所以我們可以過載個運算子,按想要的方式排序就好。
交點只需要計算橫座標,直接連立求解就可以啦。
看一下簡短的**。
#include#include#include
#include
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using
namespace
std;
typedef
long
long
ll;const
int m = 200005
;int
read()
while(ch >= '
0' && ch <= '9'
)
return ans *op;
}
struct
node
}line[m];
double solve(int p,int q)//
計算交點位置
intn,stack[m],top,ans[m];
intmain()
sort(ans,ans+top+1);//
把答案排個序
rep(i,1,top) printf("
%d "
,ans[i]);
return0;
}
HNOI 2008 水平可見直線
hnoi 2008 水平可見直線 在 xoy 直角座標平面上有n條直線 l1,l2,ln,若在y 值為正無窮大處往下看,能見到 li的某個子線段,則稱 li為可見的,否則 li為被遮蓋的。例如,對於直線 l1 y x l2 y x l3 y 0 則 l1和l2是可見的,l3是被遮蓋的。給出 n 條直...
HNOI 2008 水平可見直線
傳送門 題目描述 在 xo yxoy xoy 直角座標平面上有 n nn 條直線 l1,l2,l nl 1,l 2,l n l1 l2 ln 若在 y yy 值為正無窮大處往下看,能見到 l il i li 的某個子線段,則稱 l il i li 為可見的,否則 l il i li 為被覆蓋的。例如...
HNOI2008 水平可見直線
luogu 給定若干條直線 都是 y ax b 的形式 求從上往下看所有可以看到的直線,從小往大輸出編號 n le 50000 a b le 500000 從上往下看,若干條直線構成的半平面交的部分才是可見的 聽說直接做半平面交可以 o n log n 做,但是我不會 y kx b 對於乙個 x 只...