[JSOI2008]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|<=106
提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。

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

思路
线段树标记永久化。见我的博客[Heoi2013]Segment

代码

#include <cstdio>

const int maxn=100000;
const int maxx=50000;

struct line
{
  double k,b;

  double f(int x)
  {
    return k*x+b;
  }
};

struct segment_tree
{
  int val[(maxx<<2)+10],totl;
  double topv;
  line li[maxn+10];

  int insert(int now,int left,int right,int insv)
  {
    if(left>right)
      {
        return 0;
      }
    int uol=li[insv].f(left)>li[val[now]].f(left);
    int uor=li[insv].f(right)>li[val[now]].f(right);
    int mid=(left+right)>>1;
    if((!val[now])||(uol&&uor))
      {
        val[now]=insv;
      }
    else if(uol^uor)
      {
        double c=(li[insv].b-li[val[now]].b)/(li[val[now]].k-li[insv].k);
        if((c<=mid)&&uol)
          {
            insert(now<<1,left,mid,insv);
          }
        else if((c<=mid)&&uor)
          {
            insert(now<<1,left,mid,val[now]);
            val[now]=insv;
          }
        else if((c>mid)&&uol)
          {
            insert(now<<1|1,mid+1,right,val[now]);
            val[now]=insv;
          }
        else if((c>mid)&&uor)
          {
            insert(now<<1|1,mid+1,right,insv);
          }
      }
    return 0;
  }

  inline int ins(double a,double b)
  {
    ++totl;
    li[totl].k=b;
    li[totl].b=a-b;
    insert(1,1,maxx,totl);
    return 0;
  }

  int query(int now,int left,int right,int pos)
  {
    double ff=li[val[now]].f(pos);
    if(ff>topv)
      {
        topv=ff;
      }
    if(left==right)
      {
        return 0;
      }
    int mid=(left+right)>>1;
    if(pos<=mid)
      {
        query(now<<1,left,mid,pos);
      }
    if(pos>mid)
      {
        query(now<<1|1,mid+1,right,pos);
      }
    return 0;
  }

  inline int ask(int p)
  {
    topv=0;
    query(1,1,maxx,p);
    int ans=topv/100;
    return ans;
  }
};

segment_tree st;
int n;
char s[10];

int main()
{
  scanf("%d",&n);
  while(n--)
    {
      scanf("%s",s);
      if(s[0]=='P')
        {
          double a,b;
          scanf("%lf%lf",&a,&b);
          st.ins(a,b);
        }
      else
        {
          int a;
          scanf("%d",&a);
          printf("%d\n",st.ask(a));
        }
    }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值