洛谷 P4254 [JSOI2008]Blue Mary开公司 线段树

版权声明:2333 https://blog.csdn.net/liangzihao1/article/details/82499508

题目背景
Blue Mary 最近在筹备开一家自己的网络公司。由于他缺乏经济头脑,所以先后聘请了若干个金融顾问为他设计经营方案。

题目描述
万事开头难,经营公司更是如此。开始的收益往往是很低的,不过随着时间的增长会慢慢变好。也就是说,对于一个金融顾问 i ,他设计的经营方案中,每天的收益都比前一天高,并且均增长一个相同的量 P i

由于金融顾问的工作效率不高,所以在特定的时间,Blue Mary 只能根据他已经得到的经营方案来估算某一时间的最大收益。由于 Blue Mary 是很没有经济头脑的,所以他在估算每天的最佳获益时完全不会考虑之前的情况,而是直接从所有金融顾问的方案中选择一个在当天获益最大的方案的当天的获益值,例如:

有如下两个金融顾问分别对前四天的收益方案做了设计:

第一天 第二天 第三天 第四天 P i
顾问 1 1 5 9 13 4
顾问 2 2 5 8 11 3
在第一天,Blue Mary认为最大收益是 2(使用顾问 2 的方案),而在第三天和第四天,他认为最大收益分别是 9 和 13(使用顾问 1 的方案)。而他认为前四天的最大收益是:
2 + 5 + 9 + 13 = 29
现在你作为 Blue Mary 公司的副总经理,会不时收到金融顾问的设计方案,也需要随时回答 Blue Mary 对某天的“最大收益”的询问(这里的“最大收益”是按照 Blue Mary 的计算方法)。一开始没有收到任何方案时,你可以认为每天的最大收益值是 0。下面是一组收到方案和回答询问的例子:

询问 2
回答 0
收到方案:0 1 2 3 4 5 ……
询问 2
回答 1
收到方案:2 2.1 2.2 2.3 2.4 ……
询问 2
回答 2.1
输入输出格式

输入格式:
第一行 :一个整数 N ,表示方案和询问的总数。

接下来 N 行,每行开头一个单词 Q u e r y P r o j e c t

若单词为 Q u e r y ,则后接一个整数 T ,表示 Blue Mary 询问第 T 天的最大收益。

若单词为 P r o j e c t ,则后接两个实数 S P ,表示该种设计方案第一天的收益 S ,以及以后每天比上一天多出的收益 P

输出格式:
对于每一个 Q u e r y ,输出一个整数,表示询问的答案,并精确到整百元(以百元为单位,例如:该天最大收益为 210 或 290 时,均应该输出 2)。没有方案时回答询问要输出 0。

输入输出样例

输入样例#1:
10
Project 5.10200 0.65000
Project 2.76200 1.43000
Query 4
Query 2
Project 3.80200 1.17000
Query 2
Query 3
Query 1
Project 4.58200 0.91000
Project 5.36200 0.39000
输出样例#1:
0
0
0
0
0
说明

数据范围:

1 N 100000 , 1 T 50000 , 0 < P < 100 , S ∣≤ 10 5

提示:
本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。

分析:
维护一次函数最值。
这个显然可以用平衡树维护凸壳,不过有一种比较好写的线段树。
一个区间维护这个区间的最优势线段。
这时加入了一条新的线段(区间里显然叫线段),考虑 m i d 的处的值和斜率。
假如加入的的线段斜率更大,且 m i d 处也更大,这条线段比之前的更优势,然后插入线段变为了这个区间的线段,递归处理左半部;否则直接处理右半部。斜率小同理。
至于查询最值,要把包含 x 的所有区间的直线都带人一边。

代码:

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>

const int maxn=5e4;

using namespace std;

int n,x;
char s[50];

struct rec{
    double k,b;
    double get(double x)
    {
        return k*x+b;
    }
}t[maxn*4],d;

void ins(int p,int l,int r,rec d)
{
    if (l==r)
    {
        if (t[p].get(l)<d.get(l)) t[p]=d;
        return;
    }
    int mid=(l+r)/2;
    if (d.k>t[p].k)
    {
        if (d.get(mid)>t[p].get(mid))
        {
            ins(p*2,l,mid,t[p]);
            t[p]=d;
        }
        else ins(p*2+1,mid+1,r,d);
    }
    else
    {
        if (d.get(mid)>t[p].get(mid))
        {
            ins(p*2+1,mid+1,r,t[p]);
            t[p]=d;
        }
        else ins(p*2,l,mid,d);
    }
}

double getmax(int p,int l,int r,int x)
{   
    if (l==r) return t[p].get(x);
    int mid=(l+r)/2;
    double tmp;
    if (x<=mid) tmp=getmax(p*2,l,mid,x);
           else tmp=getmax(p*2+1,mid+1,r,x);
    return max(tmp,t[p].get(x));
}

int main()
{
    scanf("%d",&n); 
    for (int i=1;i<=n;i++)
    {
        scanf("%s",s);
        if (s[0]=='P')
        {
            scanf("%lf%lf",&d.b,&d.k);
            d.b-=d.k;
            ins(1,1,maxn,d);
        }
        else
        {
            scanf("%d",&x);
            printf("%d\n",(int)getmax(1,1,maxn,x)/100);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/82499508
今日推荐