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

1568: [JSOI2008]Blue Mary开公司

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

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 

然后查询某x位置所有直线中的最大值。

我们需要用到标记永久化的思想。每次加入一条直线,先判断直线的斜率和本区间记录的直线的斜率,再判断区间中点哪条直线的答案大,如果是斜率大的直线答案大,因为斜率递增,所以在[mid+1,r]中斜率小的直线不会再产生贡献,那么我们把当前区间的答案更改为斜率大的直线,同时将斜率小的直线向[l,mid]中下方。如果是斜率小的直线的答案大,那么斜率大的直线只可能在[mid+1,r]中产生贡献,那么就把当前区间的答案更改为斜率较小的直线,并把斜率大的直线向[mid+1,r]下方。

查询答案的时候就把经过的区间所记录的直线该点的值都计算一下,取最大值就是答案。

#include
#include
#include
#include
#include
#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]



你可能感兴趣的:(线段树)