3860. 【NOIP2014八校联考第3场第2试10.5】地壳运动

Description

JZ是一个坐落在地壳运动活跃的山区的城市,常受地质灾害的袭击。
城市中建立了N个应急避难所以躲避灾害,这些避难所从1~N编号。此外有M条道路连接这些避难所,所有避难所间均可通过这M条道路直接或间接到达。由于是在规划良好的市区,道路可以由若干个平行于x或y坐标轴的线段组成,所以避难所xi和yi之间的道路可以用(ui,vi)来表示,道路的长度为ui+vi。由于地壳运动会导致地面拉伸或收缩,可用两个实数k1,k2描述城市的伸缩程度,此时某条道路的实际长度变为ui*k1+vi*k2。有若干个独立的询问,每次询问给出k1和k2,政府都希望在此地壳运动前提下,以最小的花费维护其中一些道路,使得只用这些被维护的道路仍能使所有避难所间相互连通。因为花费与道路的实际总长成正比,所以你需要对每一次询问求出被维护道路的最短实际总长。

Input

第一行三个整数N,M,Q,分别表示避难所数量、道路数量、询问数量。
接下来M行每行四个整数xi,yi,ui,vi。xi,yi表示道路连接的两个避难所编号,ui,vi意义如上文所述。
最后Q行每行两个实数,表示每次询问的的k1和k2。

Output

输出Q行,每行一个实数,表示实际总长,保留三位小数。

Sample Input

4 8 3
2 1 3 6
3 2 0 7
4 1 7 0
1 4 4 6
2 1 2 7
1 2 2 10
2 2 5 5
4 4 8 9
0.626436771146 0.472537839745
0.977631137354 0.190235819672
0.418883351791 0.221987861358

Sample Output

12.253
9.671
6.878

Data Constraint

对于30%的数据,N<=30,M<=3000,Q<=3000。
对于另外30%的数据,N<=20,M<=25000,Q<=10000
对于100%的数据,N<=35,M<=25000,Q<=200000,1<=xi,yi<=N,0<=ui,vi<=10^6。

Solution

我们考虑对于(u1,v1)和(u2,v2),当前者更优时,有:u1*k1+v1*k2<u2*k1+v2*k2,则

(u1-u2)*k1<(v2-v1)*k2

当u1>u2时,u1-u2>0,则不等号方向不变,k1/k2<(v2-v1)/(u1-u2),那么我们可以将所有的u按照从大到小排序,然后维护一个凸包,对于每个询问,同样维护k1/k2的升序的离线询问,那么对于每一条重边,我们就在凸包中线性查找最优的决策点,然后将一共n^2条边取出来做最小生成树即可。注意一定要有prim不能用kruskal,因为带个log时间就翻倍了。

Code

#include<cstdio> 
#include<algorithm>
#include<cstdlib>
#include <cctype>
#define I int
#define db double
#define L ls[id]
#define F(i,a,b) for(register I i=a;i<=b;++i)
#define Fd(i,a,b) for(register I i=a;i>=b;--i)
#define N 37
#define M 25002
using namespace std;
I n,m,Q,x,y,k,id,u,v,bz[N],t,TE=0,ls[N*N],nx[M];db f[N][N],p[N];
struct to{I u,v;}a[M],b[M];struct rd{I x,y,u,v;}d[M];struct e{I x,y;db s;}E[N*N];struct qry{db k1,k2,s;I id;}q[200002];
inline I cmp(qry x,qry y){return x.k1*y.k2<y.k1*x.k2;}
inline I cmp2(qry x,qry y){return x.id<y.id;}
inline I cmpd(rd x,rd y){return x.x<y.x||x.x==y.x&&x.y<y.y||x.x==y.x&&x.y==y.y&&x.u>y.u;}
inline void add(I x,I u,I v){a[++TE]=to{u,v};nx[TE]=ls[x],ls[x]=TE;}
inline I gd(I x){return (d[x].x-1)*n+d[x].y;}
inline signed iut(){
	int ans=0;char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
I main(){
	n=iut(),m=iut(),Q=iut();
	F(i,1,m){d[i]=rd{iut(),iut(),iut(),iut()};if(d[i].x>d[i].y) swap(d[i].x,d[i].y);}
	sort(d+1,d+1+m,cmpd);
	t=0;
	F(i,1,m){
		id=gd(i);
		while(t>1&&(db)(b[t].v-b[t-1].v)/(b[t-1].u-b[t].u)>(db)(d[i].v-b[t].v)/(b[t].u-d[i].u)) t--;
		b[++t]=to{d[i].u,d[i].v};
		if(i==m||id!=gd(i+1)){Fd(j,t,1) add(id,b[j].u,b[j].v);t=0;}
	}
	F(i,1,Q){scanf("%lf%lf",&q[i].k1,&q[i].k2);q[i].id=i;}
	sort(q+1,q+1+Q,cmp);
	F(o,1,Q){
		F(x,1,n){
			bz[x]=0,p[x]=1e9;
			F(y,x+1,n) if(ls[id=(x-1)*n+y]){
				while(nx[L]&&(a[nx[L]].v-a[L].v)*q[o].k2<q[o].k1*(a[L].u-a[nx[L]].u)) L=nx[L];
				f[x][y]=f[y][x]=a[L].u*q[o].k1+a[L].v*q[o].k2;
			}
			else f[x][y]=f[y][x]=1e9;
		}
		p[1]=0;
		F(i,1,n){
			x=0;
			F(j,1,n) if(!bz[j]&&(!x||p[x]>p[j])) x=j;
			bz[x]=1,q[o].s+=p[x];
			F(j,1,n) p[j]=f[x][j]<p[j]?f[x][j]:p[j];
		}
	}
	sort(q+1,q+1+Q,cmp2);
	F(i,1,Q) printf("%.03lf\n",q[i].s);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/104281816