BZOJ4858 : [Jsoi2016]炸弹攻击 2

枚举每个$S$作为原点,将所有$D$和$T$极角排序。

枚举每个$T$,那么另一个$T$需要和当前的$T$夹角不超过$180$度,贡献为内部$D$的个数。

双指针后用前缀和查询区间的贡献即可。

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

 

#include<cstdio>
#include<algorithm>
const int N=810;
int D,S,T,i,j,k,cnt,s[N*4],f[N*4],g[N*4];long long ans;
struct P{
  int x,y,t;
  P(){}
  P(int _x,int _y,int _t){x=_x,y=_y,t=_t;}
  int sgn()const{return x?x>0:y>0;}
}a[N],b[N],c[N],e[N*4];
inline bool cmp(const P&a,const P&b){
  if(a.sgn()!=b.sgn())return a.sgn()<b.sgn();
  return 1LL*a.x*b.y<1LL*a.y*b.x;
}
int main(){
  scanf("%d",&D);
  for(i=1;i<=D;i++)scanf("%d%d",&a[i].x,&a[i].y);
  scanf("%d",&S);
  for(i=1;i<=S;i++)scanf("%d%d",&b[i].x,&b[i].y);
  scanf("%d",&T);
  for(i=1;i<=T;i++)scanf("%d%d",&c[i].x,&c[i].y);
  for(i=1;i<=S;i++){
    cnt=0;
    for(j=1;j<=D;j++)e[++cnt]=P(a[j].x-b[i].x,a[j].y-b[i].y,0);
    for(j=1;j<=T;j++)e[++cnt]=P(c[j].x-b[i].x,c[j].y-b[i].y,1);
    std::sort(e+1,e+cnt+1,cmp);
    for(j=1;j<=cnt;j++)e[j+cnt]=e[j];
    for(j=1;j<=cnt*2;j++){
      s[j]=s[j-1],f[j]=f[j-1],g[j]=g[j-1];
      if(e[j].t)f[j]++,g[j]+=s[j];else s[j]++;
    }
    for(j=k=1;j<=cnt;j++)if(e[j].t){
      if(k<j)k=j;
      while(k+1<j+cnt&&1LL*e[j].x*e[k+1].y<=1LL*e[j].y*e[k+1].x)k++;
      ans+=g[k]-g[j]-s[j]*(f[k]-f[j]);
    }
  }
  return printf("%lld",ans),0;
}

  

posted @ 2017-12-12 01:58 Claris 阅读(...) 评论(...) 编辑 收藏