请求开大时限
查看原帖
请求开大时限
817668
Hukaidi8566楼主2025/2/6 20:17

使用平衡树维护动态凸壳,第9个点本地1.8s~1.9s。

C和C++都是后两个点超时,改double后仅优化0.003s。

#include<cstdio>
//#include<iostream>
//using namespace std;

const int nn=100005;
const long double SMALL=1e-14;

int n;
long double A[100005],B[100005],C[100005];

long double f[100005];
long double X[100005],Y[100005];

int Insert(int,int,int);
void Newnod(int);
int root,ch[100005][2],fa[100005];

void Splayy(int,int);
void Rotate(int);
int Getson(int);
int Prepre(int);
int Secsec(int);

long double slope(int,int);

int Finddd(long double);

long double maxx(long double x,long double y)
{
	if(x>y) return x;
	return y;
}

int main()
{
	scanf("%d%Lf",&n,&f[0]);
	for(int i=1;i<=n;i++) scanf("%Lf%Lf%Lf",&A[i],&B[i],&C[i]);
	
	for(int i=1;i<=n;i++)
	{
		int j=Finddd(-A[i]/B[i]);
		
		f[i]=maxx(f[i-1],X[j]*A[i]+Y[j]*B[i]);
		Y[i]=f[i]/(A[i]*C[i]+B[i]),X[i]=f[i]*C[i]/(A[i]*C[i]+B[i]);
		
		root=Insert(root,0,i);
		Newnod(i);
	}
	
	printf("%.3Lf",f[n]);
	
	return 0;
}
int Insert(int u,int father,int num)
{
	if(!u)
	{
		fa[num]=father;
		return num;
	}
	
	if(X[num]<X[u]) ch[u][0]=Insert(ch[u][0],u,num);
	else ch[u][1]=Insert(ch[u][1],u,num);
	
	return u;
}
void Newnod(int num)
{
	Splayy(num,0);
	int P=Prepre(num);
	if(P) Splayy(P,num);
	int S=Secsec(num);
	if(S) Splayy(S,num);
	
	if(P&&X[num]<X[P]+SMALL)
	{
		if(Y[P]<Y[num])
		{
			int pp=Prepre(P);
			if(pp)
			{
				Splayy(pp,num);
				ch[pp][1]=0;
			}
			else  ch[num][0]=0;
			P=pp;
		}
		else
		{
			ch[P][1]=S;
			if(S) fa[S]=P;
			root=P;
			fa[P]=0;
			return;
		}
	}
	if(S&&X[S]<X[num]+SMALL)
	{
		if(Y[S]<Y[num])
		{
			int ss=Secsec(S);
			if(ss)
			{
				Splayy(ss,num);
				ch[ss][0]=0;
			}
			else ch[num][1]=0;
			S=ss;
		}
		else
		{
			ch[S][0]=P;
			if(P) fa[P]=S;
			root=S;
			fa[S]=0;
			return;
		}
	}
	if(!P&&!S) return;
	
	if(P&&S&&slope(P,S)+SMALL>=slope(num,P))
	{
		ch[S][0]=P;
		fa[P]=S;
		root=S;
		fa[S]=0;
		return;
	}
	
	int pp=0;
	if(P) pp=Prepre(P);
	while(pp)
	{
		if(X[pp]+SMALL>X[P]) puts("wrong");
		
		Splayy(pp,P);
		if(slope(P,num)>=slope(pp,P));
		else break;
		
		ch[num][0]=pp;
		fa[pp]=num;
		P=pp;
		pp=ch[P][0];
		while(ch[pp][1]) pp=ch[pp][1];
	}
	
	int ss=0;
	if(S) ss=Secsec(S);
	while(ss)
	{
		Splayy(ss,S);
		if(slope(num,S)<=slope(S,ss));
		else break;
		
		ch[num][1]=ss;
		fa[ss]=num;
		S=ss;
		ss=ch[S][1];
		while(ch[ss][0]) ss=ch[ss][0];
	}
	
	return;
}
void Splayy(int x,int mb)
{
	if(x==mb) return;
	int y,z;
	while(fa[x]!=mb)
	{
		y=fa[x];z=fa[y];
		if(z!=mb)
		{
			if(Getson(x)==Getson(y)) Rotate(y);
			else Rotate(x);
		}
		Rotate(x);
	}
	if(!mb) root=x;
	return;
}
void Rotate(int x)
{
	int y=fa[x];int z=fa[y];
	int k1=Getson(x),k2=Getson(y);
	
	if(ch[x][!k1]) fa[ch[x][!k1]]=y;
	ch[y][k1]=ch[x][!k1];
	fa[y]=x;
	ch[x][!k1]=y;
	fa[x]=z;
	if(z) ch[z][k2]=x;
	
	return;
}
int Getson(int x)
{
	return ch[fa[x]][1]==x;
}
int Prepre(int x)
{
	int now=root,res=0;
	while(now)
	{
		if(X[now]<X[x]||X[now]<X[x]+SMALL&&now<x)
		{
			res=now;
			now=ch[now][1];
		}
		else now=ch[now][0];
	}
	return res;
}
int Secsec(int x)
{
	int now=root,res=0;
	while(now)
	{
		if(X[x]<X[now]||X[x]<X[now]+SMALL&&x<now)
		{
			res=now;
			now=ch[now][0];
		}
		else now=ch[now][1];
	}
	return res;
}
long double slope(int p1,int p2)
{
	return (Y[p2]-Y[p1])/(X[p2]-X[p1]);
}
int Finddd(long double x)
{
	if(!ch[root][0]&&!ch[root][1]) return root;
	
	int res=root,u=root;
	while(u)
	{
		int P=Prepre(u);
		
		long double K;
		if(!P) K=0;
		else K=slope(u,P);
		
		if(K+SMALL>=x)
		{
			res=u;
			u=ch[u][1];
		}
		else u=ch[u][0];
	}
	
	return res;
}
2025/2/6 20:17
加载中...