【JZOJ5390】逗气

来源:互联网 发布:搜索引擎优化教程 编辑:程序博客网 时间:2024/04/28 20:20

Description

这里写图片描述

Solution

这题首先把绝对值拆掉,发现它是这样一个东西:bjajdi+cidi(ajci),我们发现cidi对我们求解没有影响,先去掉,然后就是这个东西ajdi+bj,于是对于每一个aj,bj,可以当作一个一次函数f(x)=ajx+bj,那么这里的di就作为自变量x。现在对于一个di要求最大值,那么也就是求当前所加入的直线与x=di这条与y轴平行线的交点的最高点。

那么我们有经典做法线段树:区间[l,r]记录在此区间内往上露出最长长度的线段(你可以理解为一束光在这个区间内从上往下照,照到长度最多的线段)(对于这题是直线),那么更新就维护区间的性质即可(如果没有则直接覆盖,有则选择向上露出长度多的那条,剩下的那条往下更新区间)。查询也很容易,就从根一直往下找这个位置取最大值就可以了。

Code

#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)#define N 200010#define inf 10000000000000000ll#define ll long longusing namespace std;struct node{    int x,y;    int wz;}w1[N],w2[N];bool cmp(node x,node y){    return x.x<y.x;}struct tree{    int l,r,o;}tr[N];struct line{    int k,b;    ll f(int x){        return (ll)k*x+b;    }}ln[N];int cc=1,tot=0;void pdl(int v){    if(!tr[v].l) tr[v].l=++cc;}void pdr(int v){    if(!tr[v].r) tr[v].r=++cc;}double meet(int x,int y){    return (ln[y].b-ln[x].b)*1.0/(ln[x].k-ln[y].k);}void change(int v,int l,int r,int x){    if(!tr[v].o) {tr[v].o=x;return;}    int o=tr[v].o;    double p=meet(x,o);    int mid=(l+r)/2;    if(p<=l*1.0 || p>=r*1.0 || ln[x].k==ln[o].k)    {        if(ln[x].f(mid)>ln[o].f(mid)) tr[v].o=x;        return;    }    if(p<=mid*1.0)    {        pdl(v);        if(ln[x].k>ln[o].k) tr[v].o=x,change(tr[v].l,l,mid,o);        else change(tr[v].l,l,mid,x);    }    else    {        pdr(v);        if(ln[x].k<ln[o].k) tr[v].o=x,change(tr[v].r,mid+1,r,o);        else change(tr[v].r,mid+1,r,x);    }}ll find(int v,int l,int r,int x){    if(!v) return -inf;    int o=tr[v].o;    if(!o) return -inf;    ll tmp=ln[o].f(x);    if(l==r) return tmp;    int mid=(l+r)/2;    if(x<=mid) return max(tmp,find(tr[v].l,l,mid,x));    else return max(tmp,find(tr[v].r,mid+1,r,x));}int lf=1;void add(int x){    ln[++tot].k=lf*w1[x].x,ln[tot].b=w1[x].y;}ll z[N];int main(){    freopen("gas.in","r",stdin);    freopen("gas.out","w",stdout);    int n,m;    scanf("%d %d",&n,&m);    int mx=0;    fo(i,1,n) scanf("%d %d",&w1[i].x,&w1[i].y),mx=max(mx,max(w1[i].x,w1[i].y));    fo(i,1,m) scanf("%d %d",&w2[i].x,&w2[i].y),w2[i].wz=i,mx=max(mx,max(w2[i].x,w2[i].y));    sort(w1+1,w1+n+1,cmp),sort(w2+1,w2+m+1,cmp);    int p=0;    fo(i,1,m)    {        while(w1[p+1].x<=w2[i].x && p<n) p++,add(p),change(1,1,mx,tot);        int wz=w2[i].wz;        z[wz]=max(z[wz],find(1,1,mx,w2[i].y)-(ll)w2[i].x*w2[i].y);    }    lf=-1,p=n+1;    memset(tr,0,sizeof(tr)),tot=0,cc=1;    fd(i,m,1)    {        while(w1[p-1].x>=w2[i].x && p>1) p--,add(p),change(1,1,mx,tot);        int wz=w2[i].wz;        z[wz]=max(z[wz],find(1,1,mx,w2[i].y)+(ll)w2[i].x*w2[i].y);    }    fo(i,1,m) printf("%lld\n",z[i]);}