zoukankan      html  css  js  c++  java
  • BZOJ4617 : [Wf2016]Spin Doctor

    将所有点投射到二维平面上,枚举形成答案的两个$1$类点作为端点,以及过这两点的两条平行直线,那么答案就是直线边上以及内部的点数。

    显然只需要枚举$1$类点形成的凸包上的点。

    如果只有一个$1$类点,那么答案是$1$。

    如果凸包大小为$1$,那么只有和它重合的$0$类点会被计入答案。

    如果凸包大小为$2$,那么只有线段上的所有点会被计入答案。

    否则凸包大小至少为$3$,对于每个$0$类点,首先在凸包上按极角二分出一条边,看看是否在凸包内或者边上。

    如果不在,那么往左往右二分出两条切线的位置,当平行线的斜率介于这之间时会夹住这个点。

    求出所有关键事件后扫描线即可。

    时间复杂度$O(nlog n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=250010;
    int n,m,ce,i,j,x,y,z,ca,cb,cnt,ret,mv;
    struct P{
      int x,y;
      P(){}
      P(int _x,int _y){x=_x,y=_y;}
      P operator-(const P&b){return P(x-b.x,y-b.y);}
      void operator-=(const P&b){*this=*this-b;}
      bool operator==(const P&b){return x==b.x&&y==b.y;}
      bool operator!=(const P&b){return x!=b.x||y!=b.y;}
    }a[N],b[N],c[N<<1];
    struct E{
      P o;int t;
      E(){}
      E(P _o,int _t){
        o=_o,t=_t;
        if(o.x<0)o.x*=-1,o.y*=-1;
      }
    }e[N<<1];
    inline bool cmp(const P&a,const P&b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    inline ll cross(const P&a,const P&b){return 1LL*a.x*b.y-1LL*a.y*b.x;}
    inline bool cmpe(const E&a,const E&b){return cross(a.o,b.o)<0;}
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    int convexhull(P*p,int n,P*q){
      int i,k,m;
      for(i=m=0;i<n;q[m++]=p[i++])while(m>1&&cross(q[m-1]-q[m-2],p[i]-q[m-2])<=0)m--;
      k=m;
      for(i=n-2;i>=0;q[m++]=p[i--])while(m>k&&cross(q[m-1]-q[m-2],p[i]-q[m-2])<=0)m--;
      return --m;
    }
    inline bool point_on_segment(P p,P a,P b){
      return !cross(b-a,p-a)&&1LL*(p.x-a.x)*(p.x-b.x)+1LL*(p.y-a.y)*(p.y-b.y)<=0;
    }
    inline int askl(int l,int r,P p){
      int t=l++,mid;
      while(l<=r){
        mid=(l+r)>>1;
        if(cross(c[mid]-p,c[(mid-1+n)%n]-c[mid])<=0)l=(t=mid)+1;else r=mid-1;
      }
      return t;
    }
    inline int askr(int l,int r,P p){
      int t=r--,mid;
      while(l<=r){
        mid=(l+r)>>1;
        if(cross(c[mid]-p,c[(mid+1)%n]-c[mid])>=0)r=(t=mid)-1;else l=mid+1;
      }
      return t;
    }
    inline void solve(P p){
      if(point_on_segment(p,c[0],c[n-1])){cnt++;return;}
      int o=0;
      if(p.x>0){
        int l=1,r=n-1,mid;
        while(l<=r)if(cross(c[mid=(l+r)>>1],p)>=0)l=(o=mid)+1;else r=mid-1;
      }else if(p.y>0)o=n-1;
      if(p.x>=0&&cross(p-c[o],c[o+1]-p)<0){cnt++;return;}
      if(p.x>=0&&point_on_segment(p,c[o],c[o+1])){cnt++;return;}
      int l,r;
      if(p.x>0)l=askl(0,o,p),r=askr(o,n,p);else l=askl(m,n,p),r=askr(0,m,p);
      e[++ce]=E(p-c[l],1);
      e[++ce]=E(p-c[r],-1);
      if(cmpe(e[ce],e[ce-1]))cnt++;
    }
    int main(){
      read(n);
      while(n--){
        read(x),read(y),read(z);
        if(z)a[++ca]=P(x,y);else b[++cb]=P(x,y);
      }
      if(ca==1)return puts("1"),0;
      cnt=ca;
      sort(a+1,a+ca+1,cmp);
      for(ca=0,i=1;i<=cnt;i++)if(i==1||a[i]!=a[i-1])a[++ca]=a[i];
      if(ca==1){
        for(i=1;i<=cb;i++)if(b[i]==a[1])cnt++;
        return printf("%d",cnt),0;
      }
      if(ca==2){
        for(i=1;i<=cb;i++)if(point_on_segment(b[i],a[1],a[2]))cnt++;
        return printf("%d",cnt),0;
      }
      n=convexhull(a+1,ca,c);
      for(i=1;i<n;i++)c[i]-=c[0];
      for(i=1;i<=cb;i++)b[i]-=c[0];
      c[0]-=c[0];
      for(i=0;i<n;i++)if(c[i].x>=c[m].x)m=i;
      for(i=0;i<n;i++)c[i+n]=c[i];
      for(i=1;i<=cb;i++)solve(b[i]);
      sort(e+1,e+ce+1,cmpe);
      for(i=1;i<=ce;i=j){
        for(j=i;j<=ce&&!cross(e[i].o,e[j].o);j++)ret+=e[j].t;
        if(ret<mv)mv=ret;
      }
      return printf("%d",cnt+mv),0;
    }
    

      

  • 相关阅读:
    Oracle 获取表结构信息
    EasyUI layout动态设置Split属性
    jquery easyui-datagrid 如何清空数据
    ORacle 复制表
    aspx调用webmethod
    RDLC添加链接
    Nginx 负载均衡 ip_hash , hash key(consistent) url_hash, least_conn
    Nginx 提升吞吐量利器 Keeplived
    Nginx Gzip 的正确使用
    Nginx 切割日志
  • 原文地址:https://www.cnblogs.com/clrs97/p/6624951.html
Copyright © 2011-2022 走看看