• [CTSC2010]产品销售


    先考虑流。
    (s->i)连流量(d_i)费用(0)
    (i->t)连流量(u_i)费用(p_i)
    (i->i+1)连流量(inf)费用(c_i)
    (i+1->i)连流量(inf)费用(m_i)
    然而我们并不能通过此题。
    考虑从左到右枚举所有和源点连边的边进行增广。这样子的好处是不用考虑向左增广后的反向边,且时间复杂度可以保证。
    我们需要找到当前边向左/右的最短路。
    当前边向右的最短路:由于我们后面的边都没有增广过,所以我们一定不会走反向边。
    可以用一个线段树维护,线段树的下标(x)表示当前点到(x)的最短路。如果一个点和汇点连的边代价变为(0),需要把这条边在线段树上删除(赋值为(inf)
    当前边向左的最短路:可能会走反向边。如果一条原边被反向边覆盖,则我们一定会走这条边上的反向边。
    考虑用另一个线段树维护权值和我们当前反向边的流量,线段树的下标(x)表示:
    如果反向边有流量,则是反向边的流量,否则是(inf)
    每次在线段树上找到最小值的位置。然后把第二个线段树上权值为(0)的下标都赋值成(inf),且在第一颗线段树上进行修改。
    找到第二个线段树上为(0)的值可以寻找最小值。
    增广流量:(min(最小值位置到t的流量,当前点到最小值位置的流量,s到当前点的流量))
    维护当前点到前面是否是反向边可以用差分数组。
    在当前点增广完后,使用差分数组判定当前点到前面的反向边流量。
    分析复杂度:一条边在被向右增广时复杂度显然是(O(nlog_2n))
    在被向左增广时,由于我们从左到右增广,所以当前边的流量显然会先增加,后减少。最终只会减到(0)一次。
    而只有减到(0)才会贡献复杂度(O(log_2n))
    同时,与源点/汇点相邻的边只有减到(0)才会贡献复杂度(O(log_2n))
    所以总时间复杂度(O(nlog_2n))
    代码细节较多。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define N 100010
    int n,d[N],u[N],p[N],m[N],c[N],s[N];
    struct no{
    	int v,p;
    };
    int operator<(no x,no y){
    	return x.v<y.v;
    }
    struct sgt{
    	no a[N*4];
    	int tg[N*4];
    	void pd(int o){
    		if(tg[o]){
    			tg[o*2]+=tg[o];
    			tg[o*2+1]+=tg[o];
    			a[o*2].v+=tg[o];
    			a[o*2+1].v+=tg[o];
    			tg[o]=0;
    		}
    	}
    	void ad(int o,int l,int r,int x,int y,int z){
    		if(r<x||y<l)
    			return;
    		if(x<=l&&r<=y){
    			tg[o]+=z;
    			a[o].v+=z;
    			return;
    		}
    		int md=(l+r)/2;
    		pd(o);
    		ad(o*2,l,md,x,y,z);
    		ad(o*2+1,md+1,r,x,y,z);
    		a[o]=min(a[o*2],a[o*2+1]);
    	}
    	no qu(int o,int l,int r,int x,int y){
    		if(r<x||y<l)
    			return(no){1e15,0};
    		if(x<=l&&r<=y)
    			return a[o];
    		pd(o);
    		int md=(l+r)/2;
    		return min(qu(o*2,l,md,x,y),qu(o*2+1,md+1,r,x,y));
    	}
    }s1,s2;
    void bd(int o,int l,int r){
    	if(l==r){
    		s1.a[o]=(no){p[l],l};
    		s2.a[o]=(no){1e15,l};
    		return;
    	}
    	int md=(l+r)/2;
    	bd(o*2,l,md);
    	bd(o*2+1,md+1,r);
    	s1.a[o]=min(s1.a[o*2],s1.a[o*2+1]);
    	s2.a[o]=min(s2.a[o*2],s2.a[o*2+1]);
    }
    void deb(int t){
    	if(t==1){
    		for(int i=1;i<=n;i++)
    			printf("%lld ",s1.qu(1,1,n,i,i).v);
    		puts("");
    	}
    	else{
    		for(int i=1;i<=n;i++)
    			printf("%lld ",s2.qu(1,1,n,i,i).v);
    		puts("");
    	}
    }
    signed main(){
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&d[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&u[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&p[i]);
    	for(int i=1;i<n;i++)
    		scanf("%lld",&m[i]);
    	for(int i=1;i<n;i++)
    		scanf("%lld",&c[i]);
    	bd(1,1,n);
    	for(int i=1;i<n;i++)
    		s1.ad(1,1,n,i+1,n,c[i]);
    	int ans=0;
    	for(int i=1;i<=n;i++){
    		while(d[i]){
    			no pl=s1.qu(1,1,n,1,i),pr=s1.qu(1,1,n,i+1,n);
    			if(pl<pr){
    				int x=pl.p;
    				no pp=s2.qu(1,1,n,x,i);
    				int f=min(d[i],min(u[x],pp.v));
    				d[i]-=f;
    				u[x]-=f;
    				ans+=f*pl.v;
    				if(!u[x])
    					s1.ad(1,1,n,x,x,1e15);
    				if(pp.v){
    					s2.ad(1,1,n,x,i-1,-f);
    					while(1){
    						pp=s2.qu(1,1,n,x,i-1);
    						if(pp.v)
    							break;
    						x=pp.p;
    						s1.ad(1,1,n,1,x,c[x]+m[x]);
    						s2.ad(1,1,n,x,x,1e15);
    					}
    				}
    			}
    			else{
    				int x=pr.p,f=min(d[i],u[x]);
    				d[i]-=f;
    				u[x]-=f;
    				ans+=f*pr.v;
    				s[i]+=f;
    				s[x]-=f;
    				if(!u[x])
    					s1.ad(1,1,n,x,x,1e15);
    			}
    		}
    		s1.ad(1,1,n,1,i,m[i]);
    		s1.ad(1,1,n,i+1,n,-c[i]);
    		s[i]+=s[i-1];
    		if(s[i]){
    			s1.ad(1,1,n,1,i,-c[i]-m[i]);
    			s2.ad(1,1,n,i,i,-1e15+s[i]);
    		}
    	}
    	printf("%lld",ans);
    }
    
  • 相关阅读:
    生成随机《c和指针笔记》让rand更随机一点
    mvcframeworkProgramming ASP.NET MVCFundamentals of ASP.NET MVC(四)Controller
    直线距离uva 11168 Airport(训练指南)
    分量算法poj 1751 Highways 最小生成树之Kruskal(克鲁斯卡尔)算法
    图片对象android学习笔记之使用ClipDrawable
    汇总窗口Visual Studio Watch 窗口技巧汇总
    百度用户百度,来一场华丽的视觉盛宴吧
    Dynamic 动态类型 和双问号??的使用
    C# insert into 一条记录后获取该记录的自动增长列ID
    MVC JsonResult的使用
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14162569.html
Copyright © 2020-2023  润新知