[jzoj3865/JSOI2014]士兵部署
2017-10-19 16:40
260 查看
题目大意
给定平面上n个整点。m次询问,每次给出一个整点P,问n个点加上P之后形成的凸包面积为多少。n,m≤100000
分析
首先可以给n个点求个凸包,然后就是计算加上P之后凸包增加的面积。先判掉凸包是一个点或线段的情况。接下来讲一般情况。
如果能找到过点P的两个切线就可以求增加的面积了。
假设P在凸包外面,那么可以考虑先随便在凸包上确定一个点Q,然后直线PQ和凸包有两个交点(如果这条直线恰好是一条切线则只有一个交点)。这样可以把凸包分成两部分,每一部分以P为原点相邻之间求叉积正好是一段正数一段负数,可以二分求切线。
现在问题是如何求另一个交点。容易发现以P为原点时,凸包上除Q外的点也满足一段在PQ左边,一段在PQ右边。所以也可以二分找交点。
确定了两条切线后,可以用叉积求增加的面积。把式子拆开就是一个区间和的形式了。
时间复杂度O(nlogn)
#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 ,Out; struct P { int x,y; P () {} P (int _x,int _y) { x=_x; y=_y; } }A ,B ,D ,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; }
相关文章推荐
- jzoj3865[JSOI2014]士兵部署
- JSOI2014第三轮 DAY2T2 士兵部署
- [JZOJ3864]【JSOI2014】歌剧表演
- 【jzoj3861】【JSOI2014】【支线剧情2 】【树形动态规划】
- 【JSOI2014】【JZOJ 3861】支线剧情2
- {题解}[jzoj3864]【JSOI2014】歌剧表演
- 【JSOI2014】【JZOJ 3864】歌剧表演
- 【JZOJ 3864】【JSOI2014】歌剧表演
- 【JZOJ3861】【JSOI2014】支线剧情2
- 【JZOJ 3861】【JSOI2014】支线剧情2
- JZOJ 3864. 【JSOI2014】歌剧表演
- 【JZOJ3864】【JSOI2014】歌剧表演
- [JZOJ3861]【JSOI2014】支线剧情2
- BZOJ5039: [Jsoi2014]序列维护
- db49 JZOJ 3928. 【NOIP2014模拟11.6】射击
- {题解}[jzoj3806]【NOIP2014模拟8.24】小X 的道路修建
- 【jzoj3625】【SDOI2014】【旅行(travel)】 【虚树】【lct】
- JZOJ4512. 【JSOI2016】最佳团队
- 【bzoj3875】[Ahoi2014&Jsoi2014]骑士游戏 Spfa优化dp
- jzoj 3587. 【中山市选2014】dwarf tower 暴力水题