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;
}
致歉:笔者已经意识到这是一篇几乎没有价值的文章,给您的阅读带来不好的体验,并且干扰了您的搜索环境,非常抱歉!

浙公网安备 33010602011771号