• BZOJ2640 : 可见区域


    设$base$表示直接能看到的面积,$f[i]$表示仅去掉线段$i$后新增的面积,$g[i][j]$表示仅去掉线段$i$和$j$后新增的面积。

    删除一条线段的答案为$base+max(f[i])$。

    删除两条线段的答案为$base+max(g[i][j]+f[i]+f[j],f最大值+f次大值)$。

    转一圈扫描线,按照到原点从近到远用set维护所有存在的线段。

    对于相邻两条扫描线中间的部分,找到最近的三条线段$A,B,C$,求出到原点的三角形面积$SA,SB,SC$,则$SA$贡献给$base$,$SB-SA$贡献给$f[A]$,$SC-SB$贡献给$g[A][B]$。

    由此可以发现$g$中只有$O(n)$项非$0$,可以暴力枚举。

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

    #include<cstdio>
    #include<algorithm>
    #include<set>
    #include<map>
    using namespace std;
    const int N=100010;
    inline int sgn(int x){
      if(x>0)return 1;
      if(x<0)return -1;
      return 0;
    }
    int n,ce,i,j,cg;bool in[N];
    struct P{
      int x,y;
      P(){}
      P(int _x,int _y){x=_x,y=_y;}
      int pos()const{return x?x<0:y<0;}
      P operator-(const P&b)const{return P(x-b.x,y-b.y);}
      void read(){scanf("%d%d",&x,&y);}
    }a[N][2],A,B,X,PRE;
    struct PD{
      double x,y;
      PD(){}
      PD(double _x,double _y){x=_x,y=_y;}
      double len(){return x*x+y*y;}
    };
    struct E{
      P o;int t;
      E(){}
      E(P _o,int _t){o=_o,t=_t;}
    }e[N];
    struct Num{
      double x;bool inf;
      Num(){x=0,inf=0;}
      Num(double _x,bool _inf){x=_x,inf=_inf;}
      void up(const Num&b){
        if(inf)return;
        if(b.inf){inf=1;return;}
        if(x<b.x)x=b.x;
      }
      void operator+=(const Num&b){x+=b.x,inf|=b.inf;}
      Num operator+(const Num&b)const{return Num(x+b.x,inf|b.inf);}
      void write(){if(inf)puts("infinite");else printf("%.2f
    ",x/2);}
      bool operator<(const Num&b)const{
        if(inf!=b.inf)return inf<b.inf;
        return x<b.x;
      }
    }f[N],base,ans,tmp;
    typedef pair<int,int>PI;
    typedef pair<PI,Num>PIN;
    PIN g[N];
    inline int cross(const P&a,const P&b){return a.x*b.y-a.y*b.x;}
    inline int cmpp(const P&a,const P&b){
      if(a.pos()!=b.pos())return a.pos()-b.pos();
      return sgn(cross(a,b));
    }
    inline bool cmpe(const E&a,const E&b){return cmpp(a.o,b.o)<0;}
    inline bool has_intersection(const P&a,const P&b,const P&p,const P&q){
      int d1=sgn(cross(b-a,p-a)),d2=sgn(cross(b-a,q-a));
      int d3=sgn(cross(q-p,a-p)),d4=sgn(cross(q-p,b-p));
      if(d1*d2<0&&d3*d4<0)return 1;
      return 0;
    }
    inline PD line_intersection(const P&a,const P&b,const P&p,const P&q){
      int U=cross(p-a,q-p),D=cross(b-a,q-p);
      double o=1.0*U/D;
      return PD(a.x+(b.x-a.x)*o,a.y+(b.y-a.y)*o);
    }
    inline double area(const PD&a,const PD&b){return -a.x*b.y+a.y*b.x;}
    struct cmp{
      bool operator()(int x,int y){
        double dx=line_intersection(A,X,a[x][0],a[x][1]).len(),
               dy=line_intersection(A,X,a[y][0],a[y][1]).len();
        return dx<dy;
      }
    };
    set<int,cmp>T;
    inline void change(int x){
      if(!in[x])T.insert(x);else T.erase(x);
      in[x]^=1;
    }
    inline void solve(){
      if(!cmpp(PRE,X))return;
      set<int,cmp>::iterator it=T.begin();
      static int id[3];
      static Num v[3];
      int i,o,x,y;
      for(i=0;i<3;i++)id[i]=0;
      for(i=0;i<3;i++){
        if(it==T.end())break;
        id[i]=*it;
        it++;
      }
      for(i=0;i<3;i++)if(!id[i])v[i]=Num(0,1);else{
        o=id[i];
        v[i]=Num(area(line_intersection(A,PRE,a[o][0],a[o][1]),line_intersection(A,X,a[o][0],a[o][1])),0);
      }
      for(i=2;i;i--)if(!v[i].inf)v[i].x-=v[i-1].x;
      base+=v[0];
      if(id[0])f[id[0]]+=v[1];
      if(id[0]&&id[1]){
        x=id[0],y=id[1];
        if(x>y)swap(x,y);
        g[++cg]=PIN(PI(x,y),v[2]);
      }
    }
    int main(){
      scanf("%d",&n);
      A=P(0,0);
      PRE=X=B=P(0,2000);
      for(i=1;i<=n;i++){
        a[i][0].read(),a[i][1].read();
        if(a[i][0].x>a[i][1].x)swap(a[i][0],a[i][1]);
        if(has_intersection(A,B,a[i][0],a[i][1])||a[i][0].x<0&&a[i][1].x==0&&a[i][1].y>0)change(i);
        e[++ce]=E(a[i][0],i);
        e[++ce]=E(a[i][1],i);
      }
      sort(e+1,e+ce+1,cmpe);
      for(i=1;i<=ce;i++){
        X=e[i].o;
        solve();
        change(e[i].t);
        PRE=X;
      }
      X=B;
      solve();
      base.write();
      ans=Num(0,0);
      for(i=1;i<=n;i++)ans.up(f[i]);
      ans+=base;
      ans.write();
      ans=Num(0,0);
      sort(g+1,g+cg+1);
      for(i=1;i<=cg;i=j){
        tmp=f[g[i].first.first]+f[g[i].first.second];
        for(j=i;j<=cg&&g[i].first==g[j].first;j++)tmp+=g[j].second;
        ans.up(tmp);
      }
      sort(f+1,f+n+1);
      ans.up(f[n]);
      if(n>1)ans.up(f[n]+f[n-1]);
      ans+=base;
      ans.write();
      return 0;
    }
    

      

  • 相关阅读:
    java枚举
    [bzoj3436]小K的农场【差分约束系统】【判负环】
    [bzoj1085][SCOI2005]骑士精神【暴力】
    [bzoj1034][ZJOI2008]泡泡堂BNB【贪心】
    [bzoj1046][HAOI2007]上升序列【dp】
    [bzoj1050][HAOI2006]旅行comf【MST】
    [bzoj1047][HAOI2007]理想的正方形【单调队列】
    [bzoj1004][HNOI2008]Cards【群论】
    [bzoj1045][HAOI2008] 糖果传递【构造】
    [bzoj4589]Hard Nim【FWT】
  • 原文地址:https://www.cnblogs.com/clrs97/p/10404384.html
Copyright © 2020-2023  润新知