zoukankan      html  css  js  c++  java
  • 【刷题】洛谷 P4234 最小差值生成树

    题目描述

    给定一个标号为从 (1)(n) 的、有 (m) 条边的无向图,求边权最大值与最小值的差值最小的生成树。

    输入输出格式

    输入格式:

    第一行两个数 (n, m) ,表示图的点和边的数量。

    第二行起 (m) 行,每行形如 (u_i, v_i, w_i)​ ,代表 (u_i)​ 到 (v_i)​ 间有一条长为 (w_i)​ 的无向边。

    输出格式:

    输出一行一个整数,代表你的答案。

    数据保证存在至少一棵生成树。

    输入输出样例

    输入样例#1:

    4 6

    1 2 10

    1 3 100

    1 4 90

    2 3 20

    2 4 80

    3 4 40

    输出样例#1:

    20

    说明

    对于 30% 的数据,满足 (1 leq n leq 100, 1 leq m leq 1000)

    对于 97% 的数据,满足 (1 leq n leq 500, 1 leq m leq 100000)

    对于 100% 的数据,满足 (1 leq n leq 50000, 1 leq m leq 200000, 1 leq w_i leq 10000)

    题解

    LCT

    先从对边按边权大到小排序

    然后,朴素地看,我们枚举每条边,以它的权值作为生成树的最小值,最优答案是多少。显然,如果我们确定了下界,那么上界一定是以下界为最小值的MST中的最大值。所以,枚举了最小值,那么对于它的最优答案就是所有边权大于这个最小值的边组成的图的MST中的边权的最大值减去枚举的这个最小值。

    由于已经从大到小排好序了,那么就直接不断加边,用LCT维护MST就行了

    那么对于每一次枚举,都要找一次整个MST的最大值,这个用LCT做不到,那就直接用一个数组存某条边是否在MST中,再用一个指针一直指向最前面的存在于MST中的边就行了

    当然,边权从小到大排序也可做,过程是一样的

    从小到大,维护最大生成树

    从大到小,维护最小生成树

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    const int MAXN=50000+10,MAXM=200000+10,inf=0x3f3f3f3f;
    int n,m,fa[MAXN],in[MAXM],ip=1,ans=inf;
    struct edge{
    	int u,v,w;
    	inline bool operator < (const edge &A) const {
    		return w>A.w;
    	};
    };
    edge side[MAXM];
    #define lc(x) ch[(x)][0]
    #define rc(x) ch[(x)][1]
    struct LCT{
    	int ch[MAXN+MAXM][2],fa[MAXN+MAXM],rev[MAXN+MAXM],Mx[MAXN+MAXM],id[MAXN+MAXM],stack[MAXN+MAXM],cnt,val[MAXN+MAXM];
    	inline void init()
    	{
    		memset(ch,0,sizeof(ch));
    		memset(fa,0,sizeof(fa));
    		memset(Mx,0,sizeof(Mx));
    		memset(id,0,sizeof(id));
    		memset(val,0,sizeof(val));
    		memset(rev,0,sizeof(rev));
    	}
    	inline bool nroot(int x)
    	{
    		return lc(fa[x])==x||rc(fa[x])==x;
    	}
    	inline void reverse(int x)
    	{
    		std::swap(lc(x),rc(x));
    		rev[x]^=1;
    	}
    	inline void pushup(int x)
    	{
    		Mx[x]=val[x];id[x]=x;
    		if(Mx[lc(x)]>Mx[x])Mx[x]=Mx[lc(x)],id[x]=id[lc(x)];
    		if(Mx[rc(x)]>Mx[x])Mx[x]=Mx[rc(x)],id[x]=id[rc(x)];
    	}
    	inline void pushdown(int x)
    	{
    		if(rev[x])
    		{
    			if(lc(x))reverse(lc(x));
    			if(rc(x))reverse(rc(x));
    			rev[x]=0;
    		}
    	}
    	inline void rotate(int x)
    	{
    		int f=fa[x],p=fa[f],c=(rc(f)==x);
    		if(nroot(f))ch[p][rc(p)==f]=x;
    		fa[ch[f][c]=ch[x][c^1]]=f;
    		fa[ch[x][c^1]=f]=x;
    		fa[x]=p;
    		pushup(f);
    		pushup(x);
    	}
    	inline void splay(int x)
    	{
    		cnt=0;
    		stack[++cnt]=x;
    		for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
    		while(cnt)pushdown(stack[cnt--]);
    		for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
    			if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
    		pushup(x);
    	}
    	inline void access(int x)
    	{
    		for(register int y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x);
    	}
    	inline int findroot(int x)
    	{
    		access(x);splay(x);
    		while(lc(x))pushdown(x),x=lc(x);
    		splay(x);
    		return x;
    	}
    	inline void makeroot(int x)
    	{
    		access(x);splay(x);reverse(x);
    	}
    	inline void split(int x,int y)
    	{
    		makeroot(x);access(y);splay(y);
    	}
    	inline void link(int x,int y)
    	{
    		makeroot(x);
    		if(findroot(y)!=x)fa[x]=y;
    	}
    	inline void cut(int x,int y)
    	{
    		makeroot(x);
    		if(findroot(y)==x&&fa[y]==x&&!rc(y))fa[y]=lc(x)=0,pushup(x);
    	}
    };
    LCT T;
    #undef lc
    #undef rc
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline int found(int x)
    {
    	if(fa[x]!=x)fa[x]=found(fa[x]);
    	return fa[x];
    }
    int main()
    {
    	read(n);read(m);
    	for(register int i=1;i<=n;++i)fa[i]=i;
    	for(register int i=1;i<=m;++i)read(side[i].u),read(side[i].v),read(side[i].w);
    	int dn=0;
    	std::sort(side+1,side+m+1);
    	for(register int i=1;i<=m;++i)
    	{
    		int x=found(side[i].u),y=found(side[i].v),sn=n+i;
    		if(x!=y)
    		{
    			fa[x]=y;
    			T.val[sn]=side[i].w;
    			T.link(sn,side[i].u),T.link(sn,side[i].v);
    			in[i]=1;
    			dn++;
    		}
    		else
    		{
    			if(side[i].u==side[i].v)continue;
    			T.split(side[i].u,side[i].v);
    			int so=T.id[side[i].v];
    			if(side[i].w<T.Mx[side[i].v])
    			{
    				T.val[sn]=side[i].w;
    				T.cut(so,side[so-n].u);T.cut(so,side[so-n].v);
    				in[so-n]=0;
    				T.link(sn,side[i].u);T.link(sn,side[i].v);
    				in[i]=1;
    			}
    		}
    		if(dn==n-1)
    		{
    			while(!in[ip])ip++;
    			T.split(side[i].u,side[i].v);
    			chkmin(ans,side[ip].w-side[i].w);
    		}
    	}
    	write(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    Linux0.11内核--fork进程分析
    Linux0.11内核--内存管理之1.初始化
    Linux0.11内核--进程调度分析之2.调度
    Linux0.11内核--进程调度分析之1.初始化
    github
    推荐大家一个靠谱的论文检测平台。重复的部分有详细出处以及具体修改意见,能直接在文章上做修改,全部改完一键下载就搞定了。他们现在正在做毕业季活动, 赠送很多免费字数,可以说是十分划算了!地址是:https://www.paperpass.com/
    妈妈再也不用担心我找idea激活码了
    eclipse集成tomcat
    DNS--localhost
    RFC 2819)第5节"Definitions"除外的全部内容
  • 原文地址:https://www.cnblogs.com/hongyj/p/8711426.html
Copyright © 2011-2022 走看看