BZOJ 1492 [NOI2007]货币兑换Cash

题解:斜率优化DP

用平衡树维护凸包

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=200009;
const int oo=1000000000;
const double eps=1e-9;

int dcmp(double x){
	if(fabs(x)<eps)return 0;
	if(x>0)return 1;
	else return -1;
}

int n;
double A[maxn],B[maxn],R[maxn],f[maxn];
double Getx(int i){
	return f[i]*R[i]/(R[i]*A[i]+B[i]);
}
double Gety(int i){
	return f[i]/(R[i]*A[i]+B[i]);
}
double GetK(int i,int j){
	double xi=Getx(i),yi=Gety(i);
	double xj=Getx(j),yj=Gety(j);
	return (yi-yj)/(xi-xj);
}

int nn=0,root=0;
int fa[maxn]={0},ch[maxn][2]={0};
double lk[maxn],rk[maxn];

int son(int x){
	if(ch[fa[x]][0]==x)return 0;
	else return 1;
}

void Rotate(int x){
	int y=fa[x];
	int z=fa[y];
	int b=son(x),c=son(y);
	int a=ch[x][b^1];
	if(z)ch[z][c]=x;
	else root=x;
	fa[x]=z;
	if(a)fa[a]=y;
	ch[y][b]=a;
	fa[y]=x;ch[x][b^1]=y;
}

void Splay(int x,int i){
	while(fa[x]!=i){
		int y=fa[x];
		int z=fa[y];
		if(z==i){
			Rotate(x);
		}else{
			if(son(x)==son(y)){
				Rotate(y);Rotate(x);
			}else{
				Rotate(x);Rotate(x);
			}
		}
	}
}

void Del(){
	int x=root;
	if((!ch[x][0])&&(!ch[x][1])){
		root=0;
	}else if(!ch[x][0]){
		root=ch[x][1];
		fa[ch[x][1]]=0;
		lk[ch[x][1]]=oo;
	}else if(!ch[x][1]){
		root=ch[x][0];
		fa[ch[x][0]]=0;
		rk[ch[x][0]]=-oo;
	}else{
		int pre=ch[x][0];
		int suc=ch[x][1];
		while(ch[pre][1])pre=ch[pre][1];
		while(ch[suc][0])suc=ch[suc][0];
		Splay(pre,x);Splay(suc,x);
		ch[pre][1]=suc;fa[suc]=pre;
		root=pre;fa[pre]=0;
		rk[pre]=lk[suc]=GetK(pre,suc);
	}
}

void Ins(int p){
	double xp=Getx(p);
	int x=root,y=0;
//	cout<<"inseting"<<endl;
	while(x){
		y=x;
		double xi=Getx(x);
		if(dcmp(xi-xp)==0){
			if(dcmp(Gety(x)-Gety(p))>=0){
				return;
			}else{
				Splay(x,0);Del();Ins(p);return;
			}
		}
		if(xp>xi)x=ch[x][1];
		else x=ch[x][0];
	}
//	cout<<"endinseting"<<endl;
	fa[x=p]=y;
	if(!y){
		root=x;
	}else{
		if(Getx(x)>Getx(y))ch[y][1]=x;
		else ch[y][0]=x;
	}
	Splay(x,0);
	int pre=ch[x][0];
	while(ch[pre][1])pre=ch[pre][1];
	int suc=ch[x][1];
	while(ch[suc][0])suc=ch[suc][0];
	if(!pre)lk[x]=oo;
	else lk[x]=rk[pre]=GetK(x,pre);
	if(!suc)rk[x]=-oo;
	else rk[x]=lk[suc]=GetK(x,suc);
}

void QueryK(double k){
	int x=root;
	while(x){
		if(lk[x]>=k&&rk[x]<=k){
			Splay(x,0);return;
		}else if(rk[x]>=k){
			if(ch[x][1]){
				x=ch[x][1];
			}else{
				Splay(x,0);return;
			}
		}else{
			if(ch[x][0]){
				x=ch[x][0];
			}else{
				Splay(x,0);return;
			}
		}
	}
}

void Getrk(int x,int p){
	int y=0;
	while(x){
		if(dcmp(lk[x]-GetK(x,p)>=0)){
			y=x;x=ch[x][1];
		}else{
			x=ch[x][0];
		}
	}
	if(y==0)return;
	Splay(y,p);
	ch[y][1]=0;
	rk[y]=lk[p]=GetK(y,p);
}
void Getlk(int x,int p){
	int y=0;
	while(x){
		if(dcmp(rk[x]-GetK(x,p))<=0){
			y=x;x=ch[x][0];
		}else{
			x=ch[x][1];
		}
	}
	if(y==0)return;
	Splay(y,p);
	ch[y][0]=0;
	rk[p]=lk[y]=GetK(y,p);
}

int main(){
	scanf("%d%lf",&n,&f[0]);
	for(int i=1;i<=n;++i)scanf("%lf%lf%lf",&A[i],&B[i],&R[i]);
	
	for(int i=1;i<=n;++i){
		double k;
		if(dcmp(B[i])==0)k=-oo;
		else k=-A[i]/B[i];
		
		f[i]=f[i-1];
		QueryK(k);
		if(root)f[i]=max(f[i],(A[i]*Getx(root)+B[i]*Gety(root)));
		
		Ins(i);
		if(root!=i)continue;
		if(lk[i]<rk[i]){
			Del();
		}else{
			if(ch[i][0]){
				Getrk(ch[i][0],i);
			}
			if(ch[i][1]){
				Getlk(ch[i][1],i);
			}
		}
	}
	
	printf("%.3f\n",f[n]);
	return 0;
}

  

posted @ 2018-03-12 11:59  ws_zzy  阅读(231)  评论(0编辑  收藏  举报