• 【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<<'
    ';
    }
    
  • 相关阅读:
    数据库之多表操作
    数据库之修改表结构
    mysql数据库
    协程
    线程
    Javaweb基础学习—— jQuery基础
    javaweb基础学习—— css
    JDBC基础学习笔记
    JDBC连接MySQL常见错误集锦
    MySQL基础笔记
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328710.html
Copyright © 2020-2023  润新知