BZOJ1769 : [Ceoi2009]tri

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

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

时间复杂度$O(n\log^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;
}

  

你可能感兴趣的:(BZOJ1769 : [Ceoi2009]tri)