zoukankan      html  css  js  c++  java
  • 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,mleq 10^6,1leq x,yleq 1000)

    题解

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

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

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

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

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

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

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

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

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

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

    时间复杂度(O(nlog 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
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    webpack 入门(1)入口(entry)出口(output
    npm 常用使用命令
    typora快捷键
    一些思考
    SED LEARN NOTE
    常用网站工具整理
    DFTC
    Notion使用技巧
    BASH LEARN NOTE
    STBC公式
  • 原文地址:https://www.cnblogs.com/autoint/p/13097943.html
Copyright © 2011-2022 走看看