1568: [JSOI2008]Blue Mary开公司
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 739 Solved: 250
[ Submit][ Status][ Discuss]
Description
Input
第一行 :一个整数N ,表示方案和询问的总数。 接下来N行,每行开头一个单词“Query”或“Project”。 若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益。 若单词为Project,则后接两个实数S,P,表示该种设计方案第一天的收益S,以及以后每天比上一天多出的收益P。
Output
对于每一个Query,输出一个整数,表示询问的答案,并精确到整百元(以百元为单位,例如:该天最大收益为210或290时,均应该输出2)。
Sample Input
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
HINT
约定: 1 <= N <= 100000 1 <= T <=50000 0 < P < 100,| S | <= 10^6 提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。
Source
题解:超哥线段树。
这道题相当于是插入n条直线y=kx+b
然后查询某x位置所有直线中的最大值。
我们需要用到标记永久化的思想。每次加入一条直线,先判断直线的斜率和本区间记录的直线的斜率,再判断区间中点哪条直线的答案大,如果是斜率大的直线答案大,因为斜率递增,所以在[mid+1,r]中斜率小的直线不会再产生贡献,那么我们把当前区间的答案更改为斜率大的直线,同时将斜率小的直线向[l,mid]中下方。如果是斜率小的直线的答案大,那么斜率大的直线只可能在[mid+1,r]中产生贡献,那么就把当前区间的答案更改为斜率较小的直线,并把斜率大的直线向[mid+1,r]下方。
查询答案的时候就把经过的区间所记录的直线该点的值都计算一下,取最大值就是答案。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 500003
using namespace std;
int n,m,tr[N*4];
double a[N*2],b[N*2];
int pd(int x,int y,int pos)
{
return a[x]+(pos-1)*b[x]>a[y]+(pos-1)*b[y];
}
void change(int now,int l,int r,int x)
{
if (l==r)
{
if (pd(x,tr[now],l))
tr[now]=x;
return;
}
int mid=(l+r)/2;
if (b[x]>b[tr[now]])
if (pd(x,tr[now],mid))
change(now<<1,l,mid,tr[now]),tr[now]=x;
else change(now<<1|1,mid+1,r,x);
if (b[x]<b[tr[now]])
if (pd(x,tr[now],mid))
change(now<<1|1,mid+1,r,tr[now]),tr[now]=x;
else change(now<<1,l,mid,x);
}
double getans(int k,int x)
{
return a[k]+(x-1)*b[k];
}
double qjmax(int now,int l,int r,int x)
{
if (l==r) return getans(tr[now],x);
int mid=(l+r)/2;
double ans=getans(tr[now],x);
if (x<=mid) ans=max(ans,qjmax(now<<1,l,mid,x));
else ans=max(ans,qjmax(now<<1|1,mid+1,r,x));
return ans;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
char s[20]; scanf("%s",s);
if (s[0]=='P')
{
m++;
scanf("%lf%lf",&a[m],&b[m]);
change(1,1,N,m);
}
else
{
int x; scanf("%d",&x);
double t=qjmax(1,1,N,x);
int k=t;
printf("%d\n",k/100);
}
}
}