BZOJ1568: [JSOI2008]Blue Mary開公司

BZOJ1568: [JSOI2008]Blue Mary開公司php

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 | <= 10^6 
提示:本題讀寫數據量可能至關巨大,請選手注意選擇高效的文件讀寫方式。

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

題解Here!
其實這個算是裸題了。。。
題目要求區間內的全部直線的最高點的最大值。
這種問題丟給 李超樹就好。。。
而後學會李超樹的能夠去看這題: BZOJ4515: [Sdoi2016]遊戲
套上一個樹剖就解決了。

步入正題:

李超樹,俗稱超哥線段樹,是國家隊隊爺李超發明出來專門解決這一類問題:html

現有2種操做:ios

1. 在平面上插入一條直線$y=kx+b$post

2. 求在$[l,r]$範圍內直線上的點的縱座標的最大值ui

對付這種問題,超哥線段樹是這麼解決的:url

假設在$[l,r]$內原有的一條直線爲$f(x)_ 1=k_1x+b_1$spa

在這個區間內加入的直線爲$f(x)_ 2=k_2x+b_2$設計

  1. 若是$f(l)_ 2>=f(l)_ 1,f(r)_ 2>=f(r)_ 1$,那麼說明$f(x)_ 1$在這個區間內被$f(x)_ 2$吊打,那麼直接替換便可。
  2. 若是$f(l)_ 2<=f(l)_ 1,f(r)_ 2<=f(r)_ 1$,那麼說明$f(x)_ 2$在這個區間內被$f(x)_ 1$吊打,那麼不作任何操做。
  3. 若是$f(l)_ 2<=f(l)_ 1,f(r)_ 2>=f(r)_ 1$或者$f(l)_ 2>=f(l)_ 1,f(r)_ 2<=f(r)_ 1$,說明兩直線在這個區間內有交點,則取區間中點$mid$,判斷兩直線在區間$[l,mid]$中是否相交:是,則右區間$[mid+1,r]$改成在上方的直線,左區間遞歸求解;否,則左區間$[l,mid]$改成在上方的直線,右區間遞歸求解。

而遞歸求解最多涉及到$log_2n$個節點。htm

因此這樣的複雜度上限是$O(log_2^2n)$。blog

而後,這題還須要用到標記永久化。

即咱們不下傳標記,在求區間最大值的時候,每次訪問到一個和詢問區間有交集的區間,把答案和這個區間所維護的線段取$min$。

附代碼:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define MUL(x) a[x].k
#define ADD(x) a[x].v
#define SIGN(x) a[x].c
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define MAXN 100010
using namespace std;
int n,m;
struct Segment_Tree{
	double data,k,v;
	bool c;
	int l,r;
}a[MAXN<<2];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline void pushup(int rt){
	DATA(rt)=max(DATA(rt),max(DATA(LSON),DATA(RSON)));
}
void buildtree(int l,int r,int rt){
	LSIDE(rt)=l;RSIDE(rt)=r;
	DATA(rt)=0;SIGN(rt)=false;
	if(l==r)return;
	int mid=l+r>>1;
	buildtree(l,mid,LSON);
	buildtree(mid+1,r,RSON);
}
void change(double k,double v,int rt){
	if(!SIGN(rt)){
		SIGN(rt)=true;
		MUL(rt)=k;ADD(rt)=v;
		DATA(rt)=max(DATA(rt),max(k*LSIDE(rt),k*RSIDE(rt))+v);
		return;
	}
	double l1=MUL(rt)*LSIDE(rt)+ADD(rt),l2=k*LSIDE(rt)+v;
	double r1=MUL(rt)*RSIDE(rt)+ADD(rt),r2=k*RSIDE(rt)+v;
	if(l2<=l1&&r2<=r1)return;
	else if(l2>l1&&r2>r1){
		MUL(rt)=k;ADD(rt)=v;
		DATA(rt)=max(DATA(rt),max(k*LSIDE(rt),k*RSIDE(rt))+v);
		return;
	}
	int mid=LSIDE(rt)+RSIDE(rt)>>1;
	double mid1=MUL(rt)*mid+ADD(rt),mid2=k*mid+v;
	if(l2<=l1){
		if(mid2<=mid1)change(k,v,RSON);
		else{
			change(MUL(rt),ADD(rt),LSON);
			MUL(rt)=k;ADD(rt)=v;
			DATA(rt)=max(DATA(rt),max(k*LSIDE(rt),k*RSIDE(rt))+v);
		}
	}
	else{
		if(mid2<=mid1)change(k,v,LSON);
		else{
			change(MUL(rt),ADD(rt),RSON);
			MUL(rt)=k;ADD(rt)=v;
			DATA(rt)=max(DATA(rt),max(k*LSIDE(rt),k*RSIDE(rt))+v);
		}
	}
	pushup(rt);
}
void update(int l,int r,double k,double v,int rt){
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
		change(k,v,rt);
		return;
	}
	int mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)update(l,r,k,v,LSON);
	if(mid<r)update(l,r,k,v,RSON);
	pushup(rt);
}
double query(int l,int r,int rt){
	double ans=0;
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
	int mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)ans=max(ans,query(l,r,LSON));
	if(mid<r)ans=max(ans,query(l,r,RSON));
	if(SIGN(rt))ans=max(ans,max(MUL(rt)*max(l,LSIDE(rt)),MUL(rt)*min(r,RSIDE(rt)))+ADD(rt));
	return ans;
}
void work(){
	char ch[15];
	while(m--){
		scanf("%s",ch);
		if(ch[0]=='P'){
			double x,y;
			scanf("%lf%lf",&x,&y);
			update(1,n,y,x-y,1);
		}
		else{
			int x=read();
			printf("%d\n",(int)query(x,x,1)/100);
		}
	}
}
void init(){
	m=read();n=MAXN-10;
	buildtree(1,n,1);
}
int main(){
	init();
	work();
    return 0;
}
相關文章
相關標籤/搜索