【JSOI2008】Blue Mary开公司 李超线段树

F.A.QsHomeDiscussProblemSetStatusRanklistContest入门OJLoginRegister捐赠本站


Notice:为保证OJ试题质量,今后添加的试题如有发现出现重复,请联系我们删除,谢谢!



Problem 1568. – [JSOI2008]Blue Mary开公司

1568: [JSOI2008]Blue Mary开公司

Time Limit: 15 Sec   Memory Limit: 162 MB
Submit: 1200   Solved: 418
[ Submit][ Status][ Discuss]

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

HINT

Source

[ Submit][ Status][ Discuss]

HOME Back


题解:李超线段树,超哥线段树一般可以处理一些区间线段的题目,可以维护线段或直线。
上个图,原图出自网络,侵删。
这里写图片描述

其实就是维护某个区间的答案,每个区间的答案就是该区间最长的那条线段的答案,有交点的部分怎么办?因为查询的时候是递归到叶子结点更新答案,所以所有应该遍历到的线段都会被遍历到。
更新答案的时候注意判断的方式,通过存储斜率k和截距b来实现。
这道题注意作弊范围和精度。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#define MAXN 100005
using namespace std;
struct node
{
    double k,b;
}tree[MAXN*8];
int n;
double min(double x,double y)
{
    if (x<y) return x;
    return y;
}
void update(int root,int l,int r,double k,double b) 
{
    if (!tree[root].b&&!tree[root].k) 
    {
        tree[root].b=b;tree[root].k=k;
        return ;
    }
    int mid=(l+r)>>1;
    double x=(mid-1.0)*tree[root].k+tree[root].b;
    double y=(mid-1.0)*k+b;
    if (l==r)
    {
        if (y>x) tree[root].k=k,tree[root].b=b;
        return;
    }
    if (tree[root].k>=k&&tree[root].b>b)
        return ;

    if (k>=tree[root].k&&b>tree[root].b)
    {
        tree[root].k=k;tree[root].b=b;
        return ;
    }
    if (tree[root].k*(l-1)+tree[root].b>k*(l-1)+b&&tree[root].k>k) return ;
    else if (tree[root].k>k)
    {
        if (x>=y)
            update(root*2,l,mid,k,b);
        else
        {
            update(root*2+1,mid+1,r,tree[root].k,tree[root].b);
            tree[root].k=k;tree[root].b=b;
        }
    }
    else
    {
        if (x>=y)
            update(root*2+1,mid+1,r,k,b);
        else
        {
            update(root*2,l,mid,tree[root].k,tree[root].b);
            tree[root].k=k;
            tree[root].b=b;
        }
    }
}
double query(int root,int l,int r,int x)
{
    int mid=(l+r)>>1;double tmp=0;
    tmp=max(tmp,(x-1.0)*tree[root].k+tree[root].b);
    if (l==r) return tmp;
    if (x<=mid) tmp=max(tmp,query(root*2,l,mid,x));
    else if (x>mid) tmp=max(tmp,query(root*2+1,mid+1,r,x));
    return tmp;
}
int main()
{
    char c[100];
    int x;double k,b;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%s",c);
        if (c[0]=='Q')
        {
            scanf("%d",&x);
            double ans=0;
            ans=query(1,1,50000,x);
            ans=floor(ans/100);
            printf("%.0lf\n",ans);
        }
        else if (c[0]=='P')
        {
            scanf("%lf%lf",&b,&k);
            update(1,1,50000,k,b);

        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值