这题其实并不怎么难,可是我现场没做出来QAQ,我还是太弱了,ORZ mjh,zyf dalao 们 tql!!!
很显然,我们可以将 aix2+bix a i x 2 + b i x 除以一个 x x ,得到,这时,要求 aix2+bix a i x 2 + b i x ,只需要在 x>0 x > 0 时求出最大的 aix+bi a i x + b i ,在 x<0 x < 0 时求出最小的 aix+bi a i x + b i ,在 x=0 x = 0 时输出 0 0 即可。
这就转化成了给定一堆直线,求出在与直线的交点的最高点或最低点。
那怎么做呢?我们先考虑 x>0 x > 0 的情况:首先,对于 ai=aj a i = a j ,如果 bi≥bj b i ≥ b j 就不用考虑 (aj,bj) ( a j , b j ) 了,这时我们会发现对于不同的 ai a i ,只有唯一的 bi b i 与之对应(即最大值)。然后呢?我们又会发现,对于一个 (ai,bi) ( a i , b i ) ,如果存在另一个 (aj,bj) ( a j , b j ) 使得 aj≥ai a j ≥ a i 且 bj≥bi b j ≥ b i ,那么也不用考虑 (ai,bi) ( a i , b i ) 了。最后,我们会发现,剩下来的直线中,对于 ai>aj a i > a j ,一定满足 bi<bj b i < b j 。我们按 ai a i 从大到小排序,那么 bi b i 递减。(由于数据范围很小, |ai|,|bi|,|x|≤32323 | a i | , | b i | , | x | ≤ 32323 ,所以直接桶排即可。)
现在我们又能发现一个性质,在这个顺序下,随着询问 x x 的递增,带来最优解的直线的下标一定是单调不下降的(这也非常好证明,因为是递增的,随着 x x 的增大,肯定是越右边带来的贡献越可能大),然后我发现这个最优解的位置并不好求,答案的判断并不满足单调性,于是我场上就想到这,GG。
当时一直困扰我的是这种情况:
会发现,当时, (a2,b2) ( a 2 , b 2 ) 比 (a1,b1) ( a 1 , b 1 ) 更优,当 x>b2−b3a3−a2 x > b 2 − b 3 a 3 − a 2 时, (a3,b3) ( a 3 , b 3 ) 比 (a2,b2) ( a 2 , b 2 ) 更优,但是由于 b2−b3a3−a2<b1−b2a2−a1 b 2 − b 3 a 3 − a 2 < b 1 − b 2 a 2 − a 1 ,所以直接统计答案并不满足任何单调性,那怎么做呢?我们会发现,当 x>b1−b3a3−a1 x > b 1 − b 3 a 3 − a 1 时, (a3,b3) ( a 3 , b 3 ) 比 (a1,b1) ( a 1 , b 1 ) 更优,又因为 b1−b3a3−a1<b1−b2a2−a1 b 1 − b 3 a 3 − a 1 < b 1 − b 2 a 2 − a 1 ,所以 (a3,b3) ( a 3 , b 3 ) 先于 (a2,b2) ( a 2 , b 2 ) 变为可能的最优解,又因为前面证到最优解的下标随着 x x 的增加而不下降,所以永远不可能成为最优解,可以直接舍去。再仔细观察,我们发现其实这也正是一个求解凸包的过程,所以由此能得出结论,最优解一定在上凸壳上,将 x x 代入上凸壳上的每条直线得到的是一个单峰函数,可以直接二分或者用单调性扫一遍(其实不用这个结论一样做QWQ)。这样的情况就做完了。 x<0 x < 0 直接反着来即可。
由于使用了桶排序,所以时间复杂度为 Θ(n+q+64647) Θ ( n + q + 64647 ) ,是线性的(实际上并没有跑多快QAQ)。
蒟蒻的暂时是全oj最快的代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int base=32323;
inline void read(int &x)
{
x=0;
bool f=false;
char ch=getchar();
while(!isdigit(ch))f^=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
if(f)x=-x;
}
struct point{
int x,y;
};
int n,q;
int a[500010],b[500010];
int qa[500010];
bool has[70010];
point p[70010];
int mx[70010];
bool ok[70010];
long long ans[70010];
inline int calc(int x,point t){return t.x*x+t.y;}
inline void getmax(int &x,int y){x=x<y?y:x;}
void work(int coef)
{
for(int i=-base;i<=base;i++)mx[i+base]=-1e9;
for(int i=1;i<=n;i++)getmax(mx[(coef>0?a[i]:-a[i])+base],(coef>0?b[i]:-b[i]));
int tot=0;
for(int i=-base;i<=base;i++)if(mx[i+base]>-1e9)p[++tot]=(point){i,mx[i+base]};
int v=-1e9;
if(coef>0)
{
for(int i=tot;i>=1;i--)
{
if(v>=p[i].y)ok[i]=false;
else
{
ok[i]=true;
v=p[i].y;
}
}
}
else
{
for(int i=1;i<=tot;i++)
{
if(v>=p[i].y)ok[i]=false;
else
{
ok[i]=true;
v=p[i].y;
}
}
}
int cnt=0;
for(int i=1;i<=tot;i++)if(ok[i])p[++cnt]=p[i];
int top=1;
for(int i=2;i<=cnt;i++)
{
while(top>1 && 1LL*(p[i].x-p[top].x)*(p[top].y-p[top-1].y)<=1LL*(p[top].x-p[top-1].x)*(p[i].y-p[top].y))top--;
p[++top]=p[i];
}
int pos=1;
int l=coef>0?1:-base,r=coef>0?base:-1;
for(int i=l;i<=r;i++)
{
if(!has[i+base])continue;
while(pos<top && calc(i,p[pos+1])>=calc(i,p[pos]))pos++;
ans[i+base]=1LL*calc(i,p[pos])*i*coef;
}
}
int main()
{
read(n);read(q);
for(int i=1;i<=n;i++)read(a[i]),read(b[i]);
for(int i=1;i<=q;i++)read(qa[i]),has[qa[i]+base]=true;
work(1);
work(-1);
for(int i=1;i<=q;i++)printf("%lld\n",ans[qa[i]+base]);
return 0;
}