• BZOJ 3963: [WF2011]MachineWorks 斜率优化 + splay动态维护凸包


    Description

    你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先进的机械设备生产先进的机器。原来的那一台生产机器已经坏了,所以你要去为公司买一台新的生产机器。你的任务是在转型期内尽可能得到更大的收益。在这段时间内,你要买卖机器,并且当机器被ACM公司拥有的时候,操控这些机器以获取利润。因为空间的限制,ACM公司在任何时候都只能最多拥有一台机器。
    在转型期内,有若干台可能卖出的机器。作为先进机器的专家,对于每台机器Mi,你已经知道了其价格Pi和可以买入的日期Di。注意,如果不在第Di天买入机器Mi,那么别的人也会买走这一台机器,也就是说,以后你将没有机会购买这台机器了。如果ACM的钱低于一台机器的价格,那么你显然不可能买到这一台机器。
    如果你在第Di天买入了机器Mi,那么ACM公司可以从第(Di)+1天开始使用这一台机器。每使用这台机器一天,就可以为公司创造出Gi美元的收益。
    你可以决定要在买入之后的某一天,以一定的折扣价卖出这一台机器。收购市场对于每一台机器,都有一个折扣价Ri。你不能在卖出的那一天使用机器,但是你可以在卖出的那一天再买入一台新的。
    在转型期结束后,ACM公司会卖掉当前所拥有的机器。你的任务就是最大化转型期间ACM公司可以得到的收入。

    Input

    输入包含若干组测试用例。每一组测试用例的第一行有3个正整数N,C和D。N是将会卖出的机器的台数(N<=10^5),C是在转型期开始时公司拥有的美元数量(C<=10^9),D是转型期持续的天数(D<=10^9)。
    之后的N行每一行描述了一台机器的情况。每一行有4个正整数Di,Pi,Ri和Gi,分别表示这台机器卖出的时间,购买这台机器需要的美元数量,卖出这台机器的折扣价和使用这台机器可以得到的利润。这些数字满足1<=Di<=D,1<=Ri<Pi<=10^9且1<=Gi<=10^9.
    最后一组测试用例后面的一行由3个0组成,表示输入数据。

    Output

    对于每一组测试用例,输出测试用例的编号,之后给出ACM公司在第D+1天结束后可以得到的最大数量的美元。
    请依照下面给出的样例输出。
     
     题解:令 $f_{i}$ 表示 $1$ ~ $i$ 的最大收入
    则 $f_{i}=f_{j}-P_{j}+R_{j}+G_{j} imes(D_{i}-D{j}-1)$
    化成一次函数形式:
    $-D_{i} imes G_{j}+F_{i}=f_{j}-P_{j}+R_{j}-G_{j}D_{j}-G_{j}$
    $x=G_{j}$,$y=f_{j}-P_{j}+R_{j}-G_{j}D_{j}-G_{j}$,$slope=-D_{j}$
    可以用斜率优化来求解.
    然而,$x$ 并不单调,所以要用平衡树来动态维护这个凸包
    我选择了 $splay$
    一定要特别注意横坐标相等的情况,一定特判是无限大还是无限小
    #include<bits/stdc++.h>
    #define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)  
    #define maxn 300000        
    #define inf 10000000000000009  
    #define ll long long 
    using namespace std;
    const long double eps = 1e-10;   
    int root;   
    int idxx[maxn];    
    struct Splaytree
    {
    	#define get(x) (ch[f[x]][1]==x) 
    	int cnt;   
    	int ch[maxn][2],f[maxn]; 
    	long double X[maxn],Y[maxn],lk[maxn],rk[maxn];    
    	// i 在前, j 在后 
    	long double slope(int i,int j) 
    	{
    		if(fabs(X[i]-X[j])<=eps) return Y[j]>Y[i] ? (long double)inf : (long double)-inf;  
    	    return (Y[i]-Y[j])/(X[i]-X[j]);   
    	 }        
    	inline void rotate(int x)
    	{
    		int old=f[x],fold=f[old],which=get(x); 
    		ch[old][which]=ch[x][which^1],f[ch[old][which]]=old; 
    		ch[x][which^1]=old,f[old]=x,f[x]=fold; 
    		if(fold) ch[fold][ch[fold][1]==old]=x;       
    	}
    	inline void splay(int x,int &tar) 
    	{
    		int fa,u=f[tar]; 
    		for(;(fa=f[x])!=u;rotate(x)) 
    			if(f[fa]!=u) 
    				rotate(get(fa)==get(x)?fa:x); 
    		tar=x; 
    	}     
    	inline int getl(int x)
    	{
    		while(ch[x][0]) x=ch[x][0]; 
    		return x; 
    	}
    	inline int getr(int x)
    	{
    		while(ch[x][1]) x=ch[x][1]; 
    		return x; 
    	}           
    	inline void insert(int &o,double x,double y,int last)
    	{
    		if(!o) 
    		{
    			o=++cnt; 
    			f[o]=last, X[o]=x,Y[o]=y;            
    			return;  
    		}              
    		insert(ch[o][x-X[o]>eps], x, y, o);            
    	}  
    	inline int getans(int x,double k)
    	{ 
    		if(!x) return 0; 
    		if(k<=lk[x]+eps&&k+eps>=rk[x]) return x; 
    		if(lk[x]<k+eps) return getans(ch[x][0], k); 
    		else return getans(ch[x][1], k);   
    	}
    	inline void del(int x)
    	{ 
    		if(!ch[x][0]) 
    		{ 
    			int right=getl(ch[x][1]); 
    			splay(right,ch[x][1]), root=right, f[root]=ch[x][1]=0;        
    			lk[root]=inf;   
    			
    		}
    		else if(!ch[x][1]) 
    		{
    			int left=getr(ch[x][0]);   
    			splay(left,ch[x][0]), root=left, f[root]=ch[x][0]=0; 
    			rk[root]=-inf;   
    		}        
    		else 
    		{
    			int left=getr(ch[x][0]),right=getl(ch[x][1]);    
    		    splay(left,ch[x][0]), splay(right,ch[x][1]); 
    		    root=left, f[root]=0, ch[root][1]=right, f[right]=root; 
    		    rk[root]=lk[right]=slope(root,right);   
    		}
    	}
    	// 平衡树上查询前驱   
    	inline int pre(int x)
    	{ 
    		int cur=ch[x][0],re=0;   
    		while(cur) 
    		{
    			if(slope(cur,x)+eps>=rk[cur])  re=cur,cur=ch[cur][0]; 
    			else cur=ch[cur][1];             
    		}
    		return re;  
    	}
    	// 平衡树上查询后继 
    	inline int nxt(int x)
    	{ 
    		int cur=ch[x][1],re=0; 
    		while(cur)
    		{
    			if(slope(x,cur)<=lk[cur]+eps) re=cur,cur=ch[cur][1];      
    			else cur=ch[cur][0]; 
    		}
    		return re;  
    	}
    	inline void maintain(int x) 
    	{
    		splay(x,root);   
    		if(ch[root][0]) 
    		{ 
    			int left=pre(root);  
    			if(left) 
    			{  
    				splay(left, ch[x][0]);  
    				ch[left][1]=f[ch[left][1]]=0;   
    				rk[left]=lk[x]=slope(left, x);   
    			}      
    			else lk[x]=-inf;  
    		}
    		else lk[x]=inf; 
    		if(ch[x][1]) 
    		{
    			int right=nxt(x);   
    			if(right) 
    			{ 
    				splay(right, ch[x][1]);
    				ch[right][0]=f[ch[right][0]]=0; 
    				rk[x]=lk[right]=slope(x, right);   
    			}
    			else rk[x]=inf;         
    		}
    		else rk[x]=-inf;          
    		if(lk[x]-rk[x]<=eps) del(x);    
    	}
    }splay; 
    int n; 
    ll d;  
    struct Node 
    {
    	ll P,D,G,R; 
    }t[maxn];   
    ll F[maxn];   
    bool cmp(Node i,Node j) { return i.D<j.D;   }
    inline void work() 
    {
        root=splay.cnt=0;       
    	int i,j=0; 
    	for(i=1;i<=n;++i) scanf("%lld%lld%lld%lld",&t[i].D,&t[i].P,&t[i].R,&t[i].G);     
    	t[++n].D=d+1; 
        t[n].P=t[n].R=t[n].G=0;         
        sort(t+1,t+1+n,cmp);  
        ll ret=F[0], re=0;        
        for(i=1;i<=n;++i) 
        {  
        	F[i]=F[i-1];  
        	if(root) 
        	{
        		j=splay.getans(root, (long double)-1.00000*t[i].D);                
        		j=idxx[j];                        
        		re=F[j]-t[j].P+t[j].R+t[j].G*(t[i].D-t[j].D-1LL);      
        		F[i]=max(F[i-1],re);                           
        	}          
        	ret=max(ret,F[i]);                                 
        	if(i!=n&&F[i]>=t[i].P) 
        	{       
        		splay.insert(root, (long double)t[i].G, (long double)(F[i]-t[i].P+t[i].R-t[i].G*(t[i].D+1LL)),0);             
        		idxx[splay.cnt]=i;            
        		splay.maintain(splay.cnt);              
        	}                                
        }    
        printf("%lld
    ",ret);        
        for(int i=0;i<=splay.cnt;++i) splay.ch[i][0]=splay.ch[i][1]=splay.f[i]=splay.lk[i]=splay.rk[i]=0;   
        root=splay.cnt=0;    
    }     
    int main()
    { 
    	for(int cas=1;;++cas) 
    	{
    		scanf("%d%lld%lld",&n,&F[0],&d); 
    		if(n==0&&F[0]==0&&d==0) break;      
    		printf("Case %d: ",cas);  
    		work();   
    	}
    	return 0; 
    }
    

      

  • 相关阅读:
    Meet Hadoop
    C++常用函数
    Summary
    获得小黄衫感想
    课程作业(八)
    课程作业(七)
    课程作业(六)
    课程作业(五)
    课程作业(四)
    课程作业(三)
  • 原文地址:https://www.cnblogs.com/guangheli/p/11150502.html
Copyright © 2020-2023  润新知