【bzoj 1568】[JSOI2008]Blue Mary开公司(超哥线段树)
1568: [JSOI2008]Blue Mary开公司
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 745 Solved: 252
[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
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
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
0
0
0
0
HINT
约定: 1 <= N <= 100000 1 <= T <=50000 0 < P < 100,| S | <= 10^6 提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。
Source
【题解】【超哥线段树】
【超哥线段树,实际上是线段树的标记永久化。】
【在这道题里,相当于向线段树里插入n条直线y=kx+b。每次加入线段时,先判断当前斜率与原来这个区间维护的斜率,再判断在区间中点哪条直线的值大。如果是斜率大的直线结果大,因为斜率是递增的,那么在[mid+1,r]里,斜率小的不会再产生影响,所以把斜率小的的标记下放,并把当前区间的答案改为大的斜率的答案;如果是斜率小的结果大,那么在[mid+1,r]里,斜率大的不会再产生影响,所以将斜率大的的标记下放,并把当前区间的答案改为小的斜率的答案。】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500010
using namespace std;
double a[N*2],b[N*2];
int tree[N*4],n,cnt;
inline int check(int i,int j,int k)
{
return (a[i]+b[i]*(k-1)>a[j]+b[j]*(k-1));
}
inline double getans(int k,int x)
{
return a[k]+b[k]*(x-1);
}
void change(int now,int l,int r,int x)
{
if(l==r)
{
if(check(x,tree[now],l)) tree[now]=x;
return;
}
int mid=(l+r)>>1;
if(b[x]>b[tree[now]])
if(check(x,tree[now],mid)) change((now<<1),l,mid,tree[now]),tree[now]=x;
else change((now<<1)|1,mid+1,r,x);
if(b[x]<b[tree[now]])
if(check(x,tree[now],mid)) change((now<<1)|1,mid+1,r,tree[now]),tree[now]=x;
else change((now<<1),l,mid,x);
}
double ask(int now,int l,int r,int x)
{
if(l==r) return getans(tree[now],x);
int mid=(l+r)>>1;
double ans=getans(tree[now],x);
if(x<=mid) ans=max(ans,ask((now<<1),l,mid,x));
if(x>mid) ans=max(ans,ask((now<<1)|1,mid+1,r,x));
return ans;
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;++i)
{
char s[20];
scanf("%s",s);
if(s[0]=='P')
{
++cnt;
scanf("%lf%lf",&a[cnt],&b[cnt]);
change(1,1,N,cnt);
}
else
{
int x;
scanf("%d",&x);
double t=ask(1,1,N,x);
int ans=t;
printf("%d\n",ans/100);
}
}
return 0;
}
既然无能更改,又何必枉自寻烦忧