BZOJ 1568 Blue Mary开公司(线段树,标记永久化)

Description

Input

第一行 :一个整数N ,表示方案和询问的总数。 
接下来N行,每行开头一个单词“Query”或“Project”。 
若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益。 
若单词为Project,则后接两个实数S,P,表示该种设计方案第一天的收益S,以及以后每天比上一天多出的收益P。
1 <= N <= 100000 1 <= T <=50000 0 < P < 100,| S | <= 10^6 
提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。

Output

对于每一个Query,输出一个整数,表示询问的答案,并精确到整百元(以百元为单位,

例如:该天最大收益为210或290时,均应该输出2)。没有方案时回答询问要输出0

Sample Input

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

Sample Output

0
0
0
0
0

题意:

对于二维坐标系,两种操作

• 1. 插入一条射线,以x=1为起点

• 2. 查询横坐标为X (整数)时所有射线y值的最大值

分析:

• 新加入一条射线可能会影响若干区间

• 即最后区间[a,b]的答案可能由”折线”组成

• 考虑标记永久化。即对于线段树上的每个点 (代表一个区间)除非 由严格更优的射线出现,否则不删除此线段 (新线段直接下传)

• 按照斜率及区间中点处取值分四种情况讨论 • 画图说明

• 如何计算答案?(注意题目是单点询问)

• 答案即为X在线段树中对应的叶子到根路径上所有的点答案取max

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define mem(p,k) memset(p,k,sizeof(p));
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x3f3f3f3f
#define ll long long
#define maxn 50010

using namespace std;
double K[maxn<<2],B[maxn<<2],ans;
char S[10];
void update(double s,double p,int l,int r,int rt){
    double ft1=1.0*l*p+s,ed1=1.0*r*p+s,ft2=1.0*l*K[rt]+B[rt],ed2=1.0*r*K[rt]+B[rt];
    if(ft1<=ft2 && ed1<=ed2)return;
    if(ft1>=ft2 && ed1>=ed2){
        K[rt]=p;B[rt]=s;return;
    }
    double f=(B[rt]-s)/(p-K[rt]);
    int m=(l+r)>>1;
    if(ft1>=ft2){
        if(f<=m)update(s,p,lson);
        else update(B[rt],K[rt],rson),B[rt]=s,K[rt]=p;
    }
    else{
        if(f<=m)update(B[rt],K[rt],lson),B[rt]=s,K[rt]=p;
        else update(s,p,rson);
    }
}
void query(int k,int l,int r,int rt){
    ans=max(ans,1.0*k*K[rt]+B[rt]);
    if(l==r)return;
    int m=(l+r)>>1;
    if(k<=m)query(k,lson);
    else query(k,rson);
}
int main()
{
    int n=5e4,t;
    while(~scanf("%d",&t)){
        while(t--){
            scanf("%s",S);
            double s,p;
            int k;
            if(S[0]=='P'){
                scanf("%lf %lf",&s,&p);
                s-=p;
                update(s,p,1,n,1);
            }
            else{
                scanf("%d",&k);
                ans=0;
                query(k,1,n,1);
                printf("%lld\n",(ll)floor(ans/100.0));
            }

        }

    }

    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值