• 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;
    }
     
  • 相关阅读:
    Team Queue(队列)
    括号匹配(栈+贪心)
    string操作
    树状数组优化+dp
    最短路径变形(最大值的最小值)
    D. Ehab the Xorcist(异或和关系)
    2019 计蒜之道 第五场 A(set的应用)
    2019 计蒜之道 第三场 D(找规律+欧拉降幂)
    hdu 3507 Print Article(斜率优化dp入门题)
    oj 26319 最大子序和
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358762.html
Copyright © 2020-2023  润新知