BZOJ 1568 Blue Mary开公司

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1568

题意:两个操作:(1)添加一条直线y=kx+b;(1<=k<=100)(2)询问当前所有直线中x=t时y最大的y是多少?(1<=t<=50000)

思路:很明显,要把所有的直线维护成凸性,也就是对于任意一个x值,我们只保存y最大的那条直线。那么这个东西要能添加和删除。我们用set,set里按照斜率来建立。对于待插入的的一条直线我们首先找到与其斜率最近的两个,不妨令比其小的为pre,令比其大的为next,那么首先我们要判断要不要插入这条直线,设当前直线为cur,C(i,j)表示i与j的交点。首先我们看若cur与next的斜率相等的话,我们只需要根据其截距来判断要不要插入,若cur的截距小于等于next的截距则无需插入。接下来我们看斜率不等时。我们发现,若C(pre,cur)在next的下方,则无需插入;否则需要插入。那么一旦插入,我们就是要进行更新。比如,对于后继next以及后继的后继next1,若C(cur,next1)在next的上方,则需要将next删除。pre的删除类似。然后我们就能计算出cur在哪些区域上是最优的,[Xl,Xr],然后将该区域上标记为cur最优,这个可以用线段树。
 
struct node
{
    double k,b;
 
    node(){}
    node(double _k,double _b)
    {
        k=_k;
        b=_b;
    }
    void get()
    {
        RD(b,k);
    }
 
    bool operator<(const node &b)const
    {
        return k<b.k;
    }
};
 
 
node b[N];
 
struct Node
{
    int L,R,x;
};
 
int n;
set<node> s;
#define type set<node>::iterator
 
Node a[N<<2];
 
 
 
void pushDown(int t)
{
    if(a[t].L==a[t].R) return;
    if(a[t].x)
    {
        a[t*2].x=a[t*2+1].x=a[t].x;
        a[t].x=0;
    }
}
 
 
void build(int t,int L,int R)
{
    a[t].L=L;
    a[t].R=R;
    a[t].x=0;
    if(L==R) return;
    int mid=(L+R)>>1;
    build(t*2,L,mid);
    build(t*2+1,mid+1,R);
}
 
 
void update(int t,int L,int R,int x)
{
    if(a[t].L==L&&a[t].R==R)
    {
        a[t].x=x;
        return;
    }
    pushDown(t);
    int mid=(a[t].L+a[t].R)>>1;
    if(R<=mid) update(t*2,L,R,x);
    else if(L>mid) update(t*2+1,L,R,x);
    else
    {
        update(t*2,L,mid,x);
        update(t*2+1,mid+1,R,x);
    }
}
 
 
 
int get(int t,int pos)
{
    if(a[t].x||a[t].L==a[t].R) return a[t].x;
    pushDown(t);
    int mid=(a[t].L+a[t].R)>>1;
    if(pos<=mid) return get(t*2,pos);
    else return get(t*2+1,pos);
}
 
double cal(node a,node b)
{
    return (a.b-b.b)/(b.k-a.k);
}
 
void insert(node now)
{
    now.b-=now.k;
    type s2=s.lower_bound(now),s1=s2;
    s1--;
    node pre=*s1,sub=*s2;
    double x;
    if(now.k==sub.k)
    {
        if(now.b<=sub.b) return;
        s.erase(s2);
        s.insert(now);
    }
    else
    {
        x=(now.b-pre.b)/(pre.k-now.k);
        if(sub.k*x+sub.b>now.k*x+now.b) return;
        s.insert(now);
    }
    s2=s.find(now);s2--;
    while(s2!=s.begin())
    {
        s1=s2; s1--;
        pre=*s1,sub=*s2;
        x=cal(now,pre);
        if(sub.k*x+sub.b>now.k*x+now.b) break;
        s.erase(s2);
        s2=s.find(now);s2--;
    }
    s1=s.find(now);s1++; s2=s1;s2++;
    while(s2!=s.end())
    {
        pre=*s1,sub=*s2;
        x=cal(now,sub);
        if(pre.k*x+pre.b>now.k*x+now.b) break;
        s.erase(s1);
        s1=s.find(now);s1++; s2=s1;s2++;
    }
    b[n]=now;
    s1=s2=s.find(now);s1--;s2++;
    pre=*s1;sub=*s2;
    double x1=cal(now,pre),x2=cal(now,sub);
    int L=(int)ceil(x1),R=(int)floor(x2);
    if(L<1) L=1;
    if(R>50000) R=50000;
    if(L<=R) update(1,L,R,n);
}
 
int main()
{
    s.insert(node(0,0));
    s.insert(node(101,-INF));
    build(1,1,50000);
    int x,k;
    char op[10];
    node now;
    RD(n);
    while(n--)
    {
        RD(op);
        if(op[0]=='P') now.get(),insert(now);
        else
        {
            RD(x); k=get(1,x);
            PR((int)(b[k].k*x+b[k].b)/100);
        }
    }
}

原文地址:https://www.cnblogs.com/jianglangcaijin/p/3460042.html