[JZOJ5390]维护直线

题目大意

这里写图片描述

分析

这道题可以是维护凸壳,直线加入的斜率还是单调的,可以直接用单调栈维护,然后二分查找。
但是我比较蠢,打了线段树维护,一开始还没打出来….
来复习一下怎么线段树维护凸壳值吧。
问题:我们插入若干条直线,询问某个x的最大函数值。
方法:对于线段树一个点x,假设他代表区间为[l,r]下标代表自变量的值,中点为mid,他的两个儿子代表的区间是[l,mid-1]和[mid+1,r]。我们在这个节点只储存一条直线,满足他在mid是的函数值最大。
插入直线l1的时候,假如这个点没有直线,那么把这条直线存在这里,退出。如果有直线l2,我们要分情况讨论。

  1. yl1(mid)<yl2(mid),那么如果kl1<kl2,把l1递归进[l,mid-1],否则进入[mid+1,r]。为什么这么做呢?因为,l1在递归进去的区间里,l1有可能在一部分地方比l2大;而另外一个区间是不可能的。即使l1在任何地方都比l2差,传进去也没问题,因为我们已经保存了l2,查询的时候会碰到他,而l1有可能比l2好,我们不能放过这种可能性。
  2. yl1(mid)>yl2(mid),把上面的两条直线反过来即可,并且让x这个点储存l1。

查询自变量x的时候,我们一直递归进区间(x,x)(不存在就可能是因为他是某个mid),路上碰到的每条直线都更新一下答案。整体来看,这样做是对的。当然这个方法有些信息维护不了,更强大的方法要用平衡树。

代码

因为卡空间,我把自变量映射了一下。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
using namespace std;
#define cmax(a,b) (a=(a>b)?a:b)
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
typedef long long ll;
typedef double db;
const int N=4e5+5,mo=1e9+7;
struct rec
{
    int s,x,y,id;
}b[N];
bool operator <(rec a,rec b)
{
    return a.x<b.x||a.x==b.x&&a.s<b.s;
}
int d[N],v[N],vt,tr[N*2];
ll prt[N],ans,mx=4e18;
int n,m,i,j,k;
void clear()
{
    fo(i,1,n*4) tr[i]=0;
}
void change(int x,int l,int r,int y)
{
    if (l>r) return ;
    if (!tr[x])
    {
        tr[x]=y;
        return ;
    }
    int mid=(l+r)/2;
    ll vx=1ll*v[mid]*b[tr[x]].x+b[tr[x]].y,vy=1ll*v[mid]*b[y].x+b[y].y;
    if (vx>vy)// down vy
    {
        if (b[tr[x]].x>b[y].x)
            change(x*2,l,mid-1,y);else
            change(x*2+1,mid+1,r,y);
    }else
    {
        if (b[tr[x]].x<=b[y].x) 
            change(x*2,l,mid-1,tr[x]);else
            change(x*2+1,mid+1,r,tr[x]);
        tr[x]=y;
    }
}
void get(int x,int l,int r,int y)
{
    if (l>r||!tr[x]) return ;
    cmax(ans,1ll*b[tr[x]].x*b[y].y+b[tr[x]].y);
    int mid=(l+r)/2;
    if (b[y].y<=v[mid]) 
        get(x*2,l,mid-1,y);else
        get(x*2+1,mid+1,r,y);
}
int main()
{
    freopen("t2.in","r",stdin);
    freopen("t2.out","w",stdout);
    scanf("%d %d\n",&n,&m);
    fo(i,1,n) 
    {
        scanf("%d %d",&b[i].x,&b[i].y);
        b[i].s=0;
    }
    fo(i,1,m) 
    {
        scanf("%d %d",&b[i+n].x,&b[i+n].y);
        d[i]=b[i+n].y;
        b[i+n].s=1;
        b[i+n].id=i;
    }
    sort(b+1,b+1+n+m);
    sort(d+1,d+1+m);
    fo(i,1,m) if (d[i]!=d[i-1]) v[++vt]=d[i];
    fo(i,1,n+m)
    {
        if (!b[i].s) change(1,1,vt,i);
        else 
        {
            ans=-mx;
            get(1,1,vt,i);
            cmax(prt[b[i].id],ans-1ll*b[i].x*b[i].y);
        }
    }
    clear();
    fd(i,n+m,1)
    {
        if (!b[i].s)
        {
            b[i].x=-b[i].x;
            change(1,1,vt,i);
        }
        else
        {
            ans=-mx;
            get(1,1,vt,i);
            cmax(prt[b[i].id],ans+1ll*b[i].x*b[i].y);
        }
    }
    fo(i,1,m) printf("%lld\n",prt[i]);
}
版权声明:本文为ZLTJohn原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ZLTJohn/article/details/78128028

智能推荐

jzoj4447 【HNOI2016模拟4.14】A (维护凸壳,分段函数)

题面 分析 分开每个点求,显然一条最短路能作用很久。同一条最短路作用的部分我们是可以直接计算的。 先求出长度为k的最短路 随着时间增长,每一条路的长度都可以表示为一个一次函数 y=w+Lenx。 于是问题就变成了一次函数求凸壳。 首先我们将所有直线按w从小到大排序,然后考虑一开始两条直线,按顺序记作l1,l2。 现在要插入一条直线l3, Case0 若l3比上一条直线的斜率要大,显然是不需要考虑的...

JZOJ 3766【BJOI2014】大融合(lct维护子树大小)

Description: 小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量。 例如,在上图中,现在一共有了5条边。其中,(3,8)这条边的负载是6,因为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8)。 ...

HDU—6514 Monitor(二维差分数组维护)

Monitor Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 163840/163840 K (Java/Others) Total Submission(s): 852    Accepted Submission(s): 266   Pro...

给定直线参数在二维散点数据上绘制直线(Python)

声明: 仅个人小记 前言:遇到在二维散点图上绘制指定的直线,直线不是通过直接给出两个断点而是只给了直线的必要参数,进而需要基于散点数据计算出直线的两个端点,然后绘制出直线。方便以后使用,计算端点过程记录在这里。 一、效果展示 一批散点已经绘制 基于这批散点绘制直线 (只告知直线的斜率以及截距这些参数) 二、条件交代 前提 一堆散点数据 穿过这些散点数据的一条直线wx+b=0wx+b=0wx+b=0...

二、二维空间中的直线

1.直线的定义: 2.直线的表达式: 1)表达式一: 2)表达式二: 3)根据表达式二,如何得出该直线的正交向量以及平行向量: 3.两直线的交点 1)直线什么时候平行: 2)直线在空间中的方向向量的标准向量相同时会出现两种情况,两直线平行或者两直线重合,此时我们该如何判断呢? 3.假设两直线不平行,我们该如何求它们的交点: 4、Python代码实现:...

猜你喜欢

Linux环境下配置和安装hadoop及hadoop集群搭建(VMware)

文章目录 一、安装准备 二、hadoop的配置 1.首先配置hadoop-env.sh 2.配置core-site.xml 3.配置hdfs-site.xml 4.配置mapred-site.xml 5.配置yarn-site.xml 6.配置slaves 7.配置hadoop环境变量 三、格式化HDFS 四、启动hadoop 五、集群搭建 1.克隆虚拟机 2.配置免密登录 3.修改主机器的配置文...

使用QProcess打开和关闭第三方应用,比如CMD

使用QProcess打开和关闭第三方应用,比如CMD 注意: 很多教程不一定是对的,但我这篇绝对是对的,因为我踩坑过啊。 为了节省时间,直接上图、上代码,so easy! 重要事情说3遍: 杀死进程,一定要加/F 和 /T 杀死进程,一定要加/F 和 /T 杀死进程,一定要加/F 和 /T 开始 验证下,打开任务管理器就能看到 总结 从上面看,是不是很简单,taskkill不知道是啥,是windo...

自定义View实现注销图案的加载动画

先看效果图: 有那味了。。。(懂得都懂^ ^ √) 我们先来分析一下怎么画,然后再研究怎么让他动起来 这个View是由内部的注销图案和外面一圈圆环构成。而内部的注销图案又是由一个基本满角度的圆弧和一根竖线组成 一、绘制内部注销图案 首先初始化画笔和圆弧的外切矩形: 圆弧的中心是View的中心,坐标为(getWidth()/2,getWidth()/2),半径设置为getWidth/4,...

vue3使用vue-count-to组件

项目场景: 数据可视化大屏开发的过程中,需要实现一种滚动数字的效果,在使用vue2时,使用vue-count-to完全没有问题,功能也比较完善(滚动时长,开始值,结束值,前缀,后缀,千分隔符,小数分隔符等等),但是在vue3中使用会出现问题。 展示的效果 问题描述: 出现的错误时 == Cannot read property ‘_c’ of undefined== 这是一...

【java设计模式】中介者模式

步骤一:创建 中介者 Mediator 步骤二:建立具体中介者 实现者 步骤三:建立同事类接口 User 步骤四:建立同事类的具体实现类 步骤五:测试...