【BZOJ2395】【Balkan 2011】—Timeismoney(最小乘积生成树)

传送门

如果把每个方案的c,tc,t看做二维坐标
实际上我们就是要找到下凸壳上的所有点维护答案

考虑先找出cc最小的点AAtt最小的点BB
这2个点一定在下凸壳上

然后我们可以用(A,B)(A,B)这条直线从下往上切,切到的第一个点pp也肯定在凸包上
然后递归(A,p),(p,B)(A,p),(p,B)继续切

同时维护乘积最小值即可

由于方案的点集分布较为均匀
所以下凸壳上点期望个数只有O(log)O(log)

所以复杂度是对的

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
const int mod=998244353,g=3;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=205,M=10005;
struct pt{
	int x,y;
	pt(int _x=0,int _y=0):x(_x),y(_y){}
	friend inline pt operator +(cs pt &a,cs pt &b){
		return pt(a.x+b.x,a.y+b.y);
	}
	friend inline pt operator -(cs pt &a,cs pt &b){
		return pt(a.x-b.x,a.y-b.y);
	}
	friend inline int operator *(cs pt &a,cs pt &b){
		return 1ll*a.x*b.y-1ll*a.y*b.x;
	}
	friend inline bool operator <(cs pt &a,cs pt &b){
		return 1ll*a.x*a.y==1ll*b.x*b.y?(a.x<b.x):(1ll*a.x*a.y<1ll*b.x*b.y);
	}
	inline int dis(){
		return x*x+y*y;
	}
}ans;
struct edge{
	int u,v;ll a,b,c;
	friend inline bool operator <(cs edge &a,cs edge &b){
		return a.c<b.c;
	} 
}e[M];
int n,m;
int fa[N];
inline int find(int x){
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline pt kruscal(){
	for(int i=1;i<=n;i++)fa[i]=i;
	sort(e+1,e+m+1);pt res;
	for(int cnt=0,i=1;i<=m&&cnt<n-1;i++){
		int f1=find(e[i].u),f2=find(e[i].v);
		if(f1!=f2)fa[f1]=f2,cnt++,res=res+pt(e[i].a,e[i].b);
	}
	if(res<ans)ans=res;
	return res;
}
inline void calc(cs pt &A,cs pt &B){
	for(int i=1;i<=m;i++)e[i].c=1ll*e[i].b*(B.x-A.x)+1ll*e[i].a*(A.y-B.y);
	pt res=kruscal();
	if((A-B)*(res-B)<=0)return;
	calc(A,res),calc(res,B);
}
int main(){
	ans=pt(1e9,1e9);
	n=read(),m=read();
	for(int i=1;i<=m;i++){
		e[i].u=read()+1,e[i].v=read()+1,e[i].a=read(),e[i].b=read();
	}
	for(int i=1;i<=m;i++)e[i].c=e[i].a;
	pt A=kruscal();
	for(int i=1;i<=m;i++)e[i].c=e[i].b;
	pt B=kruscal();
	calc(A,B); 
	cout<<ans.x<<" "<<ans.y<<'
';
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328709.html