向前走莫回头❤

【bzoj 1568】[JSOI2008]Blue Mary开公司(超哥线段树)

1568: [JSOI2008]Blue Mary开公司

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 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

Sample Output

0
0
0
0
0

HINT

约定: 1 <= N <= 100000 1 <= T <=50000 0 < P < 100,| S | <= 10^6 提示:本题读写数据量可能相当巨大,请选手注意选择高效的文件读写方式。

Source

[Submit][Status][Discuss]

【题解】【超哥线段树】

【超哥线段树,实际上是线段树的标记永久化。】

【在这道题里,相当于向线段树里插入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;
}


posted @ 2016-09-11 17:30  lris0-0  阅读(81)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m