1. 程式人生 > >Printed Circuit Board (board)

Printed Circuit Board (board)

 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;
}