zoukankan      html  css  js  c++  java
  • bzoj2856: [ceoi2012]Printed Circuit Board

    Description

    给出一个N个顶点的简单多边形,对于每个顶点,假如它和原点连成的线段只在这个顶点处和多边形相交,就称为满足要求的顶点。你的任务是输出所有满足要求的顶点编号。

    Input

    第一行一个正整数N。下面N行每行两个不超过106的正整数,依次表示每个顶点的坐标。顶点按照输入顺序用正整数1..N编号,并且顶点保证按照顺时针或逆时针顺序给出。

    Output

    第一行一个正整数M,表示满足要求的顶点个数。第二行M个正整数,按照升序给出满足要求的顶点编号。
     
    对所有点极角排序并离散化,特判极角相同的情况,建线段树,将所有边插到线段树上,最后查询每个点方向的射线与多边形最近的交点。
    按极角做扫描线也可以在相同复杂度内实现,但细节可能更多。
    #include<bits/stdc++.h>
    typedef long long i64;
    int min(int a,int b){return a<b?a:b;}
    int max(int a,int b){return a>b?a:b;}
    const int N=200007;
    char buf[10000001],*ptr=buf;
    int _(){
        int x=0;
        while(*ptr<48)++ptr;
        while(*ptr>47)x=x*10+*ptr++-48;
        return x;
    }
    struct pos{
        double x,y;
        double val()const{return x+y;}
    }xs[N];
    double operator*(pos a,pos b){return a.x*b.y-a.y*b.x;}
    pos operator-(pos a,pos b){return (pos){a.x-b.x,a.y-b.y};}
    int n;
    struct vertex{
        pos p;
        int id,x;
        bool operator<(vertex w)const{
            double d=p*w.p;
            return d?d<0:p.val()<w.p.val();
        }
    }vs[N];
    int ps[N],xp=0;
    bool un[N];
    struct itv{
        pos a,b;
        int l,r;
        double operator()(pos&w)const{
            return w.val()*(b*a)/(w*(a-b));
        }
    }is[533333];
    int mx;
    void ins(itv&a,itv&b){
        if(!a.r)a=b;
        else{
            int l=max(a.l,b.l),r=min(a.r,b.r);
            if(a(xs[l])+a(xs[r])>b(xs[l])+b(xs[r]))a=b;
        }
    }
    void ins(vertex a,vertex b){
        itv w=(itv){a.p,b.p,a.x,b.x};
        for(int l=a.x+mx-1,r=b.x+mx+1;r-l!=1;l>>=1,r>>=1){
            if(~l&1)ins(is[l^1],w);
            if(r&1)ins(is[r^1],w);
        }
    }
    int as[N],ap=0;
    int main(){
        fread(buf,1,sizeof(buf),stdin);
        n=_();
        for(mx=1;mx<=n+3;mx<<=1);
        for(int i=1;i<=n;++i){
            vs[i].p.x=_();
            vs[i].p.y=_();
            vs[i].id=i;
        }
        std::sort(vs+1,vs+n+1);
        for(int i=1,j=1;i<=n;i=j){
            for(++j;j<=n&&vs[i].p*vs[j].p==0;un[vs[j].id]=1,++j);
            xs[++xp]=vs[i].p;
            for(int k=i;k<j;++k)vs[k].x=xp;
        }
        for(int i=1;i<=n;++i)ps[vs[i].id]=i;
        ps[0]=ps[n];
        for(int i=1;i<=n;++i){
            int a=ps[i-1],b=ps[i];
            if(a>b)std::swap(a,b);
            if(vs[a].x<vs[b].x)ins(vs[a],vs[b]);
        }
        for(int i=1;i<=n;++i)if(!un[vs[i].id]){
            for(int w=vs[i].x+mx;w;w>>=1)if(is[w].r&&is[w](vs[i].p)<vs[i].p.val()-1e-7){
                un[vs[i].id]=1;
                break;
            }
        }
        for(int i=1;i<=n;++i)if(!un[i])as[ap++]=i;
        printf("%d
    ",ap);
        for(int i=0;i<ap;++i)printf("%d ",as[i]);
        return 0;
    }
  • 相关阅读:
    树链剖分学习笔记(未完)
    VI 配置文件(略全)
    linux之awk
    指针之基础篇
    linux之sed
    sqlplus命令手册
    Leetcode复习: 堆和栈
    leetcode 的shell部分4道题整理
    Regular Expression Matching [leetcode]
    深入浅出JAVA
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7299677.html
Copyright © 2011-2022 走看看