[jzoj3865/JSOI2014]士兵部署
来源:互联网 发布:在淘宝网上购物的步骤 编辑:程序博客网 时间:2024/05/22 12:57
题目大意
给定平面上n个整点。m次询问,每次给出一个整点P,问n个点加上P之后形成的凸包面积为多少。
n,m≤100000
分析
首先可以给n个点求个凸包,然后就是计算加上P之后凸包增加的面积。
先判掉凸包是一个点或线段的情况。接下来讲一般情况。
如果能找到过点P的两个切线就可以求增加的面积了。
假设P在凸包外面,那么可以考虑先随便在凸包上确定一个点Q,然后直线PQ和凸包有两个交点(如果这条直线恰好是一条切线则只有一个交点)。这样可以把凸包分成两部分,每一部分以P为原点相邻之间求叉积正好是一段正数一段负数,可以二分求切线。
现在问题是如何求另一个交点。容易发现以P为原点时,凸包上除Q外的点也满足一段在PQ左边,一段在PQ右边。所以也可以二分找交点。
确定了两条切线后,可以用叉积求增加的面积。把式子拆开就是一个区间和的形式了。
时间复杂度
#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int N=1e5+5;typedef long long LL;typedef double db;int n,m,Id,Top;LL ans,sum[N],Out;struct P{ int x,y; P () {} P (int _x,int _y) { x=_x; y=_y; }}A[N],B[N],D[N],Q;LL operator * (P a,P b){ return (LL)a.x*b.y-(LL)a.y*b.x;}bool operator < (P a,P b){ return a*b<0;}bool operator <= (P a,P b){ return a*b<=0;}char c;int read(){ int x=0,sig=1; for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1; for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48; return x*sig;}int main(){ n=read(); m=read(); for (int i=1;i<=n;i++) { int x=read(),y=read(); A[i]=P(x,y); } Id=1; for (int i=2;i<=n;i++) if (A[i].x<A[Id].x || A[i].x==A[Id].x && A[i].y<A[Id].y) Id=i; for (int i=1,j=0;i<=n;i++) if (i!=Id) { B[++j]=A[i]; B[j].x-=A[Id].x; B[j].y-=A[Id].y; } sort(B+1,B+n); D[Top=1]=P(0,0); for (int i=n-1;i;i--) { for (;Top>1 && P(D[Top].x-D[Top-1].x,D[Top].y-D[Top-1].y)<=P(B[i].x-D[Top-1].x,B[i].y-D[Top-1].y);Top--); D[++Top]=B[i]; } n=Top; D[n+1]=D[1]; for (int i=1;i<=n+1;i++) D[i].x+=A[Id].x,D[i].y+=A[Id].y; for (int i=3;i<=n;i++) ans+=P(D[i-1].x-D[1].x,D[i-1].y-D[1].y)*P(D[i].x-D[1].x,D[i].y-D[1].y); for (int i=2;i<=n+1;i++) sum[i]=sum[i-1]+D[i]*D[i-1]; for (int i,j,x,y,l,r,mid;m--;) { x=read(); y=read(); Q=P(D[1].x-x,D[1].y-y); if (n==1) { printf("0.0\n"); continue; } if (n==2) { printf("%.1lf\n",abs(Q*P(D[2].x-x,D[2].y-y))/2.0); continue; } if (P(D[2].x-x,D[2].y-y)<Q) { for (l=2,r=n,mid=l+r>>1;l<r;mid=l+r>>1) if (P(D[mid].x-x,D[mid].y-y)<=Q) l=mid+1;else r=mid; j=l; for (l=1,r=j,mid=j>>1;l<r;mid=l+r>>1) if (P(D[mid].x-x,D[mid].y-y)<P(D[mid+1].x-x,D[mid+1].y-y)) r=mid;else l=mid+1; i=l+1; for (l=j,r=n+1,mid=l+r>>1;l<r;mid=l+r>>1) if (P(D[mid].x-x,D[mid].y-y)<P(D[mid+1].x-x,D[mid+1].y-y)) l=mid+1;else r=mid; j=l; Out=ans+(LL)x*(D[j].y-D[i-1].y)+(LL)y*(D[i-1].x-D[j].x)+sum[j]-sum[i-1]; }else { for (l=2,r=n,mid=l+r>>1;l<r;mid=l+r>>1) if (Q<=P(D[mid].x-x,D[mid].y-y)) l=mid+1;else r=mid; j=l; for (l=1,r=j,mid=j>>1;l<r;mid=l+r>>1) if (P(D[mid].x-x,D[mid].y-y)<P(D[mid+1].x-x,D[mid+1].y-y)) l=mid+1;else r=mid; i=l; for (l=j,r=n+1,mid=l+r>>1;l<r;mid=l+r>>1) if (P(D[mid].x-x,D[mid].y-y)<P(D[mid+1].x-x,D[mid+1].y-y)) r=mid;else l=mid+1; j=l+1; Out=ans+(LL)x*(D[i].y-D[j-1].y)+(LL)y*(D[j-1].x-D[i].x)+sum[i]+sum[n+1]-sum[j-1]; } printf("%.1lf\n",Out/2.0); } return 0;}
阅读全文
0 0
- [jzoj3865/JSOI2014]士兵部署
- JSOI2014第三轮 DAY2T2 士兵部署
- 士兵
- 【JSOI2014】支线剧情
- 【JSOI2014】支线剧情2
- 【JZOJ3864】【JSOI2014】歌剧表演
- 【JSOI2014】歌剧表演
- 【JSOI2014】歌剧表演
- [JZOJ3864]【JSOI2014】歌剧表演
- bzoj5037: [Jsoi2014]电信网络
- bzoj5037: [Jsoi2014]电信网络
- {题解}[jzoj3864]【JSOI2014】歌剧表演
- 【JSOI2014】【JZOJ 3864】歌剧表演
- JZOJ 3864. 【JSOI2014】歌剧表演
- 【JZOJ 3864】【JSOI2014】歌剧表演
- 【JZOJ3861】【JSOI2014】支线剧情2
- [JZOJ3861]【JSOI2014】支线剧情2
- 3875: [Ahoi2014&Jsoi2014]骑士游戏
- yum 第三方源
- RabbitMQ--基本原理
- Spark2.2 基于Yarn的两种提交模式剖析图解
- SystemClock.sleep(long ms)与Thread.sleep(long millis)分析
- HashMap各个版本分析
- [jzoj3865/JSOI2014]士兵部署
- windows安装opencv-----VS2010+Opencv-2.4.6(附: vs2010 小技巧)
- Android与Html5互掉
- 代码注释,神兽护体,代码无bug
- Linux用户与用户组管理
- An association from the table emps refers to an unmapped class: Dept 错误解析
- 华为提出“品质宽带”价值主张 共建宽带产业新生态
- JSP的内置对象
- 51Nod-1256 乘法逆元