SCOI2019 湖之精灵的游戏

湖之精灵的游戏

一个二维平面上有\(n\)个点,第\(i\)个点的坐标是\((x_i,y_i)\),你要和湖之精灵玩游戏。

每次精灵会告诉你一个坐标\((x,y)\),连一条经过\((0,0),(x,y)\)的直线,这会把平面分成两个部分\(A,B\)。你要选择一个区间\([l,r]\),那么计算的时候只会考虑编号在\([l,r]\)之内的点。

一个半平面的价值是这个半平面中,编号在\([l,r]\)范围内的点与\((0,0),(x,y)\)组成三角形的面积之和。

你要选择一个半平面,精灵会选择另一个半平面,你需要最大化你得到的价值减去精灵得到的价值的结果。

\(m\)轮游戏,对于每轮游戏输出这个最大值乘以\(2\)的结果。

数据范围:\(n,m\leq 10^6,1\leq x,y\leq 1000\)

题解

题面的意思就是每次询问给定\((x,y)\),让你自选区间\([l,r]\),求

\[\max_{l,r}\{|\sum_{i=l}^r(xy_i-yx_i)|\} \]

利用前缀和思想观察绝对值式子

\[|x\text{sy}_r-y\text{sx}_r-(x\text{sy}_{l-1}-y\text{sx}_{l-1})| \]

为了让这个绝对值最大化,我们只需要找到最大的\(x\text{sy}_i-y\text{sx}_i\)和最小的\(x\text{sy}_j-y\text{sx}_j\)。并且绝对值符号使得我们不必拘泥于大的减小的。

怎么找最大值和最小值呢?老生常谈的斜率优化。

\[f=x\text{sy}_i-y\text{sx}_i \]

\[sy_i=\frac{y}{x}\text{sx}_i+\frac{f}{x} \]

最大值做个上凸包,最小值做个下凸包。

这个题也没有强制在线,直接双指针即可。

时间复杂度\(O(n\log n)\)

struct point {int64 x,y;};

IN point operator-(CO point&a,CO point&b){
	return {a.x-b.x,a.y-b.y};
}
IN int64 cross(CO point&a,CO point&b){
	return a.x*b.y-a.y*b.x;
}

CO int N=1e6+10;
point p[N],up[N],dn[N];
struct node {point p;int i;} q[N];
int64 ans[N];

int main(){
	freopen("lake.in","r",stdin),freopen("lake.out","w",stdout);
	int n=read<int>();
	for(int i=1;i<=n;++i)
		p[i].x=p[i-1].x+read<int>(),p[i].y=p[i-1].y+read<int>();
	int s=1;
	up[1]=p[0];
	for(int i=1;i<=n;++i){
		for(;s>=2 and cross(p[i]-up[s-1],up[s]-up[s-1])<=0;--s);
		up[++s]=p[i];
	}
	int t=1;
	dn[1]=p[0];
	for(int i=1;i<=n;++i){
		for(;t>=2 and cross(p[i]-dn[t-1],dn[t]-dn[t-1])>=0;--t);
		dn[++t]=p[i];
	}
	int m=read<int>();
	for(int i=1;i<=m;++i)
		read(q[i].p.x),read(q[i].p.y),q[i].i=i;
	sort(q+1,q+m+1,[&](CO node&a,CO node&b)->bool{
		return cross(a.p,b.p)<0;
	});
	for(int i=1,j=1;i<=m;++i){
		for(;j+1<=s and cross(q[i].p,up[j+1]-up[j])>0;++j);
		ans[q[i].i]+=cross(q[i].p,up[j]);
	}
	sort(q+1,q+m+1,[&](CO node&a,CO node&b)->bool{
		return cross(a.p,b.p)>0;
	});
	for(int i=1,j=1;i<=m;++i){
		for(;j+1<=t and cross(q[i].p,dn[j+1]-dn[j])<0;++j);
		ans[q[i].i]-=cross(q[i].p,dn[j]);
	}
	for(int i=1;i<=m;++i) printf("%lld\n",ans[i]);
	return 0;
}

posted on 2020-06-12 10:26  autoint  阅读(195)  评论(0编辑  收藏  举报

导航