题目大意
分析
这道题可以是维护凸壳,直线加入的斜率还是单调的,可以直接用单调栈维护,然后二分查找。
但是我比较蠢,打了线段树维护,一开始还没打出来….
来复习一下怎么线段树维护凸壳值吧。
问题:我们插入若干条直线,询问某个x的最大函数值。
方法:对于线段树一个点x,假设他代表区间为[l,r]下标代表自变量的值,中点为mid,他的两个儿子代表的区间是[l,mid-1]和[mid+1,r]。我们在这个节点只储存一条直线,满足他在mid是的函数值最大。
插入直线l1的时候,假如这个点没有直线,那么把这条直线存在这里,退出。如果有直线l2,我们要分情况讨论。
- yl1(mid)<yl2(mid) ,那么如果 kl1<kl2 ,把l1递归进[l,mid-1],否则进入[mid+1,r]。为什么这么做呢?因为,l1在递归进去的区间里,l1有可能在一部分地方比l2大;而另外一个区间是不可能的。即使l1在任何地方都比l2差,传进去也没问题,因为我们已经保存了l2,查询的时候会碰到他,而l1有可能比l2好,我们不能放过这种可能性。
- 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]);
}