• BZOJ1769 : [Ceoi2009]tri


    将所有点极角排序,建立线段树,线段树每个节点维护该区间内所有点组成的上下凸壳。

    对于一个查询,二分查找出相应区间的左右端点,在线段树上得到$O(log n)$个节点,在相应凸壳上三分查找出与斜边叉积最大的那个点,看看是否为正即可。

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

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=100010,E=2000000;
    int n,m,i,c,d,ans[N],g[262150],v[E],nxt[E],ed,cnt,t0,t1;
    struct P{
      int x,y;
      P(){}
      P(int _x,int _y){x=_x,y=_y;}
      P operator-(P b){return P(x-b.x,y-b.y);}
      ll operator*(P b){return 1LL*x*b.y-1LL*y*b.x;}
    }a[N],A,B,C,qA[N],qC[N],b[N],q0[N],q1[N];
    inline bool cmp(P a,P b){return a*b>0;}
    inline bool cmp0(P a,P b){return a.x==b.x?a.y>b.y:a.x<b.x;}
    inline bool cmp1(P a,P b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    inline int getl(P x){
      int l=1,r=n,mid,t=n+1;
      while(l<=r)if(x*a[mid=(l+r)>>1]>0)r=(t=mid)-1;else l=mid+1;
      return t;
    }
    inline int getr(P x){
      int l=1,r=n,mid,t=0;
      while(l<=r)if(x*a[mid=(l+r)>>1]<0)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    void add(int x,int a,int b){
      if(c<=a&&b<=d){v[++ed]=i;nxt[ed]=g[x];g[x]=ed;return;}
      int mid=(a+b)>>1;
      if(c<=mid)add(x<<1,a,mid);
      if(d>mid)add(x<<1|1,mid+1,b);
    }
    inline bool query(int x,P*q,int r){
      A=qA[x],C=qC[x];
      for(int l=0;l<=r;){
        int len=(r-l)/3,m0=l+len,m1=r-len;
        ll s0=C*(q[m0]-A),s1=C*(q[m1]-A);
        if(s0>0||s1>0)return 1;
        if(s0>s1)r=m1-1;else l=m0+1;
      }
      return 0;
    }
    void dfs(int x,int l,int r){
      if(g[x]){
        int i;
        for(cnt=0,i=l;i<=r;i++)b[cnt++]=a[i];
        for(sort(b,b+cnt,cmp0),q0[t0=0]=b[0],i=1;i<cnt;i++)if(b[i].x!=b[i-1].x){
          while(t0&&1LL*(q0[t0].y-q0[t0-1].y)*(b[i].x-q0[t0].x)<=1LL*(b[i].y-q0[t0].y)*(q0[t0].x-q0[t0-1].x))t0--;
          q0[++t0]=b[i];
        }
        for(sort(b,b+cnt,cmp1),q1[t1=0]=b[0],i=1;i<cnt;i++)if(b[i].x!=b[i-1].x){
          while(t1&&1LL*(q1[t1].y-q1[t1-1].y)*(b[i].x-q1[t1].x)>=1LL*(b[i].y-q1[t1].y)*(q1[t1].x-q1[t1-1].x))t1--;
          q1[++t1]=b[i];
        }
        for(i=g[x];i;i=nxt[i]){
          int j=v[i];
          if(ans[j])continue;
          if(query(j,q0,t0)){ans[j]=1;continue;}
          if(query(j,q1,t1))ans[j]=1;
        }
      }
      if(l==r)return;
      int mid=(l+r)>>1;
      dfs(x<<1,l,mid),dfs(x<<1|1,mid+1,r);
    }
    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 main(){
      read(n),read(m);
      for(i=1;i<=n;i++)read(a[i].x),read(a[i].y);
      sort(a+1,a+n+1,cmp);
      for(i=1;i<=m;i++){
        read(A.x),read(A.y),read(B.x),read(B.y);
        if(A*B<0)swap(A,B);
        qA[i]=A,qC[i]=B-A;
        c=getl(A),d=getr(B);
        if(c<=d)add(1,1,n);
      }
      dfs(1,1,n);
      for(i=1;i<=m;i++)puts(ans[i]?"Y":"N");
      return 0;
    }
    

      

  • 相关阅读:
    致初学者:PHP比ASP优秀的七个理由
    有情人终成眷属为好友hualex2006.12.9结婚祝福
    有情人终成眷属为好友hualex2006.12.9结婚祝福
    各种查找算法效率比较
    实习三 树、二叉树及其应用 (题目:唯一地确定一棵二叉树 )
    hdu 2188 选拔志愿者(博弈)
    hdu 1050Moving Tables(贪心)
    实习一 线性表及其应用 (题目:一元稀疏多项式的加法运算 )
    实习六 农夫过河问题
    实习二 栈、队列和递归算法设计 (题目:停车场管理 )
  • 原文地址:https://www.cnblogs.com/clrs97/p/5146689.html
Copyright © 2020-2023  润新知