Printed Circuit Board (board)
阿新 • • 發佈:2018-12-15
Printed Circuit Board (board)
題目描述
給出一個N個頂點的簡單多邊形,對於每個頂點,假如它和原點連成的線段只在這個頂點處和多邊形相交,就稱為滿足要求的頂點。你的任務是輸出所有滿足要求的頂點編號。
輸入
第一行一個正整數N。下面N行每行兩個不超過10e6的正整數,依次表示每個頂點的座標。頂點按照輸入順序用正整數1..N編號,並且頂點保證按照順時針或逆時針順序給出。
輸出
第一行一個正整數M,表示滿足要求的頂點個數。第二行M個正整數,按照升序給出滿足要求的頂點編號。
solution
計算幾何好題
首先我們按極角把點離散化了。
一條條加入邊,判斷覆蓋一個點的邊是不是他的臨邊就是答案
注意到覆蓋區間時沒必要覆蓋到底,打在區間上即可,查詢時一路統計答案。
那麼·還剩一個問題,怎麼判斷兩條邊誰前誰後。
我們用
第一條邊y較小的和第二條邊y較大的
第一條邊y較大的和第二條邊y較小的
叉積起來
畫畫圖就可以發現了
有一個細節,相同斜率的點其實不用特判。
因為那些點怎麼都不會被覆蓋。
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<map> #define db double #define ll long long #define maxn 200005 #define inf 1e9 using namespace std; int n,tot,li,ri,ans[maxn],flag[maxn],t; struct node{ int x,y,id;db k; }s[maxn]; int tr[maxn*4]; map<double,int>l; bool cmp(node a,node b){ return a.k<b.k||(a.k==b.k&&a.x<b.x); } bool C(node a,node b){ return a.id<b.id; } node xl(node a,node b){ node t;t.x=b.x-a.x;t.y=b.y-a.y;return t; } ll cr(node a,node b){ return (ll)a.x*b.y-(ll)a.y*b.x; } bool pd(int a,int b){ node p1,p2,p3,p4; p1=s[a];p2=s[a+1];if(a==n)p2=s[1]; p3=s[b];p4=s[b+1];if(b==n)p4=s[1]; if(p1.k>p2.k)swap(p1,p2);if(p3.k>p4.k)swap(p3,p4); node A=xl(p1,p4),B=xl(p2,p3); if(cr(A,B)<0)return 0;//a close else return 1; } void update(int &x,int now){ if(!x)x=now; else if(pd(x,now))x=now; } void add(int k,int l,int r,int id){ if(l>=li&&r<=ri){update(tr[k],id);return;} int mid=l+r>>1; if(li<=mid)add(k*2,l,mid,id); if(ri>mid)add(k*2+1,mid+1,r,id); } void ask(int k,int l,int r,int pl){ if(tr[k])update(t,tr[k]); if(l==r)return; int mid=l+r>>1; if(pl<=mid)ask(k*2,l,mid,pl); else ask(k*2+1,mid+1,r,pl); } int main() { cin>>n; for(int i=1;i<=n;i++){ scanf("%d%d",&s[i].x,&s[i].y);s[i].id=i; if(!s[i].x)s[i].k=inf; else s[i].k=(db)s[i].y/(db)s[i].x; } sort(s+1,s+n+1,cmp); s[0].k=-1; for(int i=1;i<=n;i++){ if(s[i].k==s[i-1].k){flag[s[i].id]=1;continue;} l[s[i].k]=++tot; } sort(s+1,s+n+1,C); for(int i=1;i<=n;i++){ li=l[s[i].k],ri=l[s[i+1].k];int D=i; if(i==n)ri=l[s[1].k]; if(li>ri)swap(li,ri); add(1,1,n,i); } for(int i=1;i<=n;i++){ t=0;ask(1,1,n,l[s[i].k]); if(i==1){if(t==n||t==1)ans[i]=1;} else {if(t==i||t==i-1)ans[i]=1;} } int sum=0; for(int i=1;i<=n;i++){ if(flag[i])continue; if(ans[i])sum++; } cout<<sum<<endl; for(int i=1;i<=n;i++){ if(flag[i])continue; if(ans[i])printf("%d ",i); } cout<<endl; return 0; }