码迷,mamicode.com
首页 > Web开发 > 详细

bzoj1568: [JSOI2008]Blue Mary开公司 三分+二分+线段树

时间:2016-08-07 00:57:06      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:

答案序列一定是个下凸壳,因此添加的等差数列与其之差是个单峰函数,可以先三分求出最值,再二分求出零点,然后用线段树,将得到的区间修改为一个等差数列。

这个做法应该比较好想吧,虽然比较慢……

#include<cstdio>
#define Z int l=1,int r=N,int k=1
#define N 50000
#define M (l+r>>1)
#define P (k<<1)
#define S (k<<1|1)
#define K l,r,k
#define L l,M,P
#define R M+1,r,S
double a[N*4],b[N*4];
void devolve(Z){
	if(b[k]){
		a[S]=a[k]+(M-l+1)
		*(b[P]=b[S]=b[k]);
		a[P]=a[k],b[k]=0;
	}
}
double query(int s,Z){
	if(l!=r){
		devolve(K);
		return s<=M
		?query(s,L)
		:query(s,R);
	}
	return a[k];
}
void amend(double u,
double v,int s,int t,Z){
	if(s==l&&t==r)
		a[k]=u,b[k]=v;
	else{
		devolve(K);
		if(t<=M)
			amend(u,v,s,t,L);
		else if(s>M)
			amend(u,v,s,t,R);
		else{
			amend(u,v,s,M,L);
			amend(u+(M-s
			+1)*v,v,M+1,t,R);
		}
	}
}
double s,t;
int i,j,m,r,l;
char k[8];
void solve(){
	scanf("%lf%lf",&s,&t);
	l=1,r=N;
	while(l!=r){
		i=l+(r-l)/3;
		j=r-(r-l)/3;
		if(t*(i-j)
		<query(i)-query(j))
			l=i+1;
		else r=j-1;
	}
	if(s+t*l-t>query(l)){
		r=l,l=1;
		while(l!=r){
			i=l+r>>1;
			if(s+t*i-t>query(i))
				r=i;
			else l=i+1;
		}
		j=l,r=N;
		while(l!=r){
			i=l+r+1>>1;
			if(s+t*i-t>query(i))
				l=i;
			else r=i-1;
		}
		amend(s+t*j-t,t,j,l);
	}
}
int main(){
	for(scanf("%d",&m);m;--m){
		scanf("%s",k);
		if(*k==80)solve();
		else{
			scanf("%d",&i);
			printf("%d\n",
			(int)query(i)/100);
		}
	}
}

  

bzoj1568: [JSOI2008]Blue Mary开公司 三分+二分+线段树

标签:

原文地址:http://www.cnblogs.com/f321dd/p/5745212.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!