欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【NOIP2017提高A组模拟9.26】逗气

程序员文章站 2023-12-24 22:55:27
...

Description

【NOIP2017提高A组模拟9.26】逗气

Input

【NOIP2017提高A组模拟9.26】逗气

Output

【NOIP2017提高A组模拟9.26】逗气

Sample Input

3 2
1 8
4 5
7 9
3 1
5 2

Sample Output

6
5

Solution

首先把所有的点按照x放到数轴上,不论是询问还是其他的普通点(x就是a[]或c[])
这样从左到右做,可以忽略绝对值
每次扫描到一个询问点就维护这个询问点的答案,这时只考虑到了x在这之前的
然后反着做一次就行了
怎么维护答案呢?
可以发现,每一个普通点都可以变成一条边,即对于每一个d的值,答案是多少
这样会有若干条线段,显然当线段重合时取最上面那条
这样可以用线段树做
也可以想成维护一个下凸壳,这个用单调队列就行了
然后二分,判断d[i]的值在哪条线段上,维护答案即可

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define N 200100
#define ll long long
using namespace std;
int n,m,d[N],tot=0,he=1,ta=0;
ll an[N];
struct node{
    ll x,y,z;
}a[N+N];
bool cnt(node x,node y){return x.x<y.x||(x.x==y.x&&x.z<y.z);}
double S(int j,int k)
{
    return (a[j].y-a[k].y)*1.0/(a[k].x-a[j].x);
}
double S1(int j,int k)
{
    return (a[j].y-a[k].y)*1.0/(a[j].x-a[k].x);
}
int main()
{
    freopen("gas.in","r",stdin);
    freopen("gas.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n) scanf("%lld%lld",&a[i].x,&a[i].y),a[i].z=0;
    fo(i,1,m) scanf("%lld%lld",&a[i+n].x,&a[i+n].y),a[i+n].z=i;
    n+=m;
    sort(a+1,a+n+1,cnt);
    fo(i,1,n)
    if(a[i].z==0)
    {
        while(ta>he&&S(d[ta],i)<S(d[ta-1],d[ta])) ta--;
        d[++ta]=i;
    }
    else
    {
        int l=he,r=ta;
        while(l+1<r)
        {
            int mid=(l+r)/2;
            if(S(d[mid-1],d[mid])<a[i].y) l=mid;else r=mid;
        }
        int k;if(S(d[l],d[r])>a[i].y) k=d[l];else k=d[r];
        an[a[i].z]=max(an[a[i].z],a[k].y-abs(a[i].x-a[k].x)*a[i].y);
    }
    he=1;ta=0;
    fd(i,n,1)
    if(a[i].z==0)
    {
        while(ta>he&&S1(d[ta],i)<S1(d[ta-1],d[ta])) ta--;
        d[++ta]=i;
    }
    else
    {
        int l=he,r=ta;
        while(l+1<r)
        {
            int mid=(l+r)/2;
            if(S1(d[mid-1],d[mid])<a[i].y) l=mid;else r=mid;
        }
        int k;if(S1(d[l],d[r])>a[i].y) k=d[l];else k=d[r];
        an[a[i].z]=max(an[a[i].z],a[k].y-abs(a[k].x-a[i].x)*a[i].y);
    }
    tot=0;
    fo(i,1,m) printf("%lld\n",an[i]);
}

上一篇:

下一篇: