P4254 [JSOI2008]Blue Mary开公司

【题意】n条直线,求x=x0与这些直线交点y的最大值

【分析】这是李超线段树的模板题,我们用线段树维护区间内,在最上方最长的是哪条直线,考虑新增直线的影响

如果新增直线完全在原区间最优直线上方,直接修改即可

如果完全在下方,那就无影响

手动画一下,分类讨论加入直线的斜率和当前区间最优直线斜率,计算mid处两条直线对应的y值,讨论一下哪条直线在那侧有影响即可

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int maxt=50005;
int n,cnt;
int maxi[maxn<<2];
double k[maxn],b[maxn];
double w(int x,int id)
{
//    if(id==2) 
//        id=id;
    return k[id]*(x-1)+b[id];
}
void update(int now,int L,int R,int id)
{
    if(L>R) return;
    if(w(L,id)>w(L,maxi[now]) && w(R,id)>w(R,maxi[now]))
    {
        maxi[now]=id;
        return;
    }
    if(w(L,id)<=w(L,maxi[now]) && w(R,id)<=w(R,maxi[now])) return;
    int mid=L+R>>1;
    if(k[id]>k[maxi[now]])
    {
        if(w(mid,id)>w(mid,maxi[now]))
        {
            update(now<<1,L,mid,maxi[now]);
            maxi[now]=id;
        }
        else
            update(now<<1|1,mid+1,R,id);
    }
    else
    {
        if(w(mid,id)<=w(mid,maxi[now]))
        {
            update(now<<1,L,mid,id);
        }
        else
        {
            update(now<<1|1,mid+1,R,maxi[now]);
            maxi[now]=id;
        }
    }
}
double query(int now,int L,int R,int v)
{
    if(L==R)
    {
        double res=w(v,maxi[now]);
        return res;
    }
    int mid=L+R>>1;
    double tmp=w(v,maxi[now]);
    if(v<=mid) return max(tmp,query(now<<1,L,mid,v));
    else return max(tmp,query(now<<1|1,mid+1,R,v));
}
int main()
{
    freopen("blue.in","r",stdin);
    freopen("blue.out","w",stdout);
    scanf("%d",&n);
    int x;
    for(int i=1;i<=n;i++)
    {
        char s[10];
        scanf("%s",s);
        if(s[0]=='P')
        {
            cnt++;
            scanf("%lf%lf",&b[cnt],&k[cnt]);
            update(1,1,maxt,cnt);
        }
        else
        {
            scanf("%d",&x);
            printf("%d\n",(int)query(1,1,maxt,x)/100);
        }
    }
    return 0;
}

 

posted @ 2021-05-10 22:35  andyc_03  阅读(39)  评论(0编辑  收藏  举报