zoukankan      html  css  js  c++  java
  • 严格次小生成树

    洛谷4180

    模板

    倍增LCA+Kruskal

    没学过这两个算法没关系,后面有讲解

    时间复杂度O(nlog_2n+mlog_2m)

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    /*
    数据中无向图不保证无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
    */
    const int maxn=1e5+10;
    const int maxm=3e5+10;
    const int INF=0x3fffffff;
    typedef long long LL;
    typedef unsigned long long ull;
    struct edge{
    	int from,to;
    	LL w;
    }ed[maxm];
    struct node{
    	int nex,to;
    	LL w;
    }e[maxn<<1];
    bool cmp(edge a,edge b){
    	return a.w<b.w;
    }
    int tot;
    int head[maxn];
    void adde(int x,int y,LL w){
    	e[++tot].nex=head[x];
    	e[tot].to=y;
    	e[tot].w=w;
    	head[x]=tot;
    }
    int n,m,fa[maxn],f[maxn][21],dep[maxn];
    //倍增LCA+Kruskal
    LL mx1[maxn][21],mx2[maxn][21],ans,mst;
    bool vis[maxm];
    int findfa(int x){
    	if(x==fa[x]) return x;
    	else return fa[x]=findfa(fa[x]);
    }
    void kruskal(){ //先求出最小生成树 
    	sort(ed+1,ed+1+m,cmp);
    	for(int i=1;i<=n;i++) fa[i]=i;
    	for(int i=1,sum=n;i<=m;i++){
    		if(sum==1) break;
    		int x=findfa(ed[i].from);
    		int y=findfa(ed[i].to);
    		if(x==y) continue;
    		vis[i]=1;
    		mst+=ed[i].w;
    		fa[x]=y;
    		sum--;
    		//在这里建边 
    		adde(ed[i].from,ed[i].to,ed[i].w);
    		adde(ed[i].to,ed[i].from,ed[i].w);
    	}
    }
    //再倍增的时候更新最小次小 
    void update(LL &max1,LL &max2,LL x,LL y){
    	if(max1==x) max2=max(max2,y);
    	else if(max1<x){
    		max2=max1;
    		max1=x;
    		max2=max(max2,y);
    	}
    	else max2=max(max2,x);
    }
    
    void dfs(int u,int fa){
    	for(int i=1;i<=20;i++){
    		f[u][i]=f[f[u][i-1]][i-1]; //倍增
    		mx1[u][i]=mx1[u][i-1];
    		mx2[u][i]=mx2[u][i-1];
    		//mx1[u][i]需要在 mx1[u][i-1] 和 mx1[f[u][i-1]][i-1]之间比较
    		//mx2也是同理
    		//注意比较的顺序(上面 
    		update(mx1[u][i],mx2[u][i],mx1[f[u][i-1]][i-1],mx2[f[u][i-1]][i-1]); 
    	}
    	for(int i=head[u];i;i=e[i].nex){
    		int v=e[i].to;
    		if(v==fa) continue;
    		dep[v]=dep[u]+1;
    		f[v][0]=u;
    		mx1[v][0]=e[i].w;  //最大的初始值 
    		dfs(v,u);   //在后面递归 
    	}
    }
    
    typedef pair<LL,LL> p; 
    
    p LCA(int x,int  y){
    	LL max1=0,max2=0;
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int i=20;i>=0;i--){
    		if(dep[f[x][i]]>=dep[y]){
    			update(max1,max2,mx1[x][i],mx2[x][i]);
    			x=f[x][i];
    		}
    	}
    	if(x==y) return make_pair(max1,max2); //返回这条路上的最大和次大值 
    	for(int i=20;i>=0;i--){
    		if(f[x][i]!=f[y][i]){
    			update(max1,max2,mx1[x][i],mx2[x][i]);
    			update(max1,max2,mx2[y][i],mx2[y][i]);
    			x=f[x][i];
    			y=f[y][i];
    		}
    	} 
    	update(max1,max2,mx1[x][0],mx2[x][0]);
    	update(max1,max2,mx1[y][0],mx2[y][0]);
    	return make_pair(max1,max2);
    }
    
    void sol(){
    	scanf("%d %d",&n,&m);
    	for(int i=1;i<=m;i++){
    		scanf("%d %d %lld",&ed[i].from,&ed[i].to,&ed[i].w);
    	}
    	kruskal();
    	dfs(1,0); //求出倍增数组 
    }
    
    void solve(){
    	ans=INF;
    	for(int i=1;i<=m;i++){
    		if(!vis[i]){
    			p temp=LCA(ed[i].from,ed[i].to);
    			if(ed[i].w==temp.first&&temp.second) ans=min(ans,ed[i].w-temp.second);
    			else if(ed[i].w>temp.first) ans=min(ans,ed[i].w-temp.first);
    		}
    	}
    	printf("%lld",ans+mst);
    } 
    
    
    
    int main(){
    	sol();
    	solve();
    return 0;
    }
    
    
    #include <bits/stdc++.h>
    #define mp make_pair
    using namespace std;
    const int maxn=1e5+10;
    const int maxe=3e5+10;
    typedef pair<long long,long long> P;
    
    inline int read(){
    	int x=0,f=1;char ch;
    	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    	return f*x;
    }
    
    struct rec{
    	int from,to;
    	long long w;
    }edge[maxe];
    bool cmp(const rec &a,const rec &b){return a.w<b.w;}
    struct node{
    	int nxt,to;
    	long long w;
    }e[maxn<<1];
    int tot=1,head[maxn];
    inline void add_edge(int from,int to,long long w){
    	e[++tot]=node{head[from],to,w},head[from]=tot;
    }
    
    int n,m,fa[maxn],f[maxn][21],dep[maxn];
    long long mx1[maxn][21],mx2[maxn][21],ans,mst;
    bool used[maxe];
    
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    
    void kruskal(){
    	sort(edge+1,edge+m+1,cmp);
    	for(int i=1;i<=n;i++)fa[i]=i;
    	for(int i=1,sum=n;i<=m;i++){
    		if(sum==1)break;
    		int x=find(edge[i].from),y=find(edge[i].to);
    		if(x!=y){
    			used[i]=1,mst+=edge[i].w,fa[x]=y,--sum;
    			add_edge(edge[i].from,edge[i].to,edge[i].w);
    			add_edge(edge[i].to,edge[i].from,edge[i].w);
    		}
    	}
    }
    
    inline void upd(long long &max1,long long &max2,long long x,long long y){
    	if(max1==x)max2=max(max2,y);
    	else if(max1<x)max2=max1,max1=x,max2=max(max2,y);
    	else max2=max(max2,x);
    }
    
    void dfs(int u,int fa){
    	for(int i=1;i<=20;i++){
    		f[u][i]=f[f[u][i-1]][i-1];
    		mx1[u][i]=mx1[u][i-1],mx2[u][i]=mx2[u][i-1];
    		upd(mx1[u][i],mx2[u][i],mx1[f[u][i-1]][i-1],mx2[f[u][i-1]][i-1]);
    	}
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;if(v==fa)continue;
    		dep[v]=dep[u]+1,f[v][0]=u,mx1[v][0]=e[i].w;
    		dfs(v,u);
    	}
    }
    
    P lca(int x,int y){
    	long long max1=0,max2=0;
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=20;i>=0;i--)
    		if(dep[f[x][i]]>=dep[y]){
    			upd(max1,max2,mx1[x][i],mx2[x][i]);
    			x=f[x][i];
    		}
    	if(x==y)return mp(max1,max2);
    	for(int i=20;i>=0;i--)
    		if(f[x][i]!=f[y][i]){
    			upd(max1,max2,mx1[x][i],mx2[x][i]);
    			upd(max1,max2,mx1[y][i],mx2[y][i]);
    			x=f[x][i],y=f[y][i];
    		}
    	upd(max1,max2,mx1[x][0],mx2[x][0]);
    	upd(max1,max2,mx1[y][0],mx2[y][0]);
    	return mp(max1,max2);
    }
    
    void read_and_parse(){
    	n=read(),m=read();
    	for(int i=1;i<=m;i++)edge[i].from=read(),edge[i].to=read(),edge[i].w=read();
    	kruskal();
    	dfs(1,0);
    }
    
    void solve(){
    	ans=0x3f3f3f3f3f3f3f3f;
    	for(int i=1;i<=m;i++)if(!used[i]){
    		P tmp=lca(edge[i].from,edge[i].to);
    		if(edge[i].w==tmp.first&&tmp.second)ans=min(ans,edge[i].w-tmp.second);
    		else if(edge[i].w>tmp.first)ans=min(ans,edge[i].w-tmp.first);
    	}
    	printf("%lld
    ",mst+ans);
    }
    
    int main(){
    	read_and_parse();
    	solve();
    	return 0;	
    } 
    

      

  • 相关阅读:
    0911内容。
    0909学习内容。
    0908学习内容
    第二天的学习内容
    第一天的学习内容
    学习目的
    jquery parents() next() prev() 找父级别标签 找同级别标签
    JQuery each遍历A标签获取href 和 里面指定的值
    jquery怎么实现点击一个按钮控制一个div的显示和隐藏
    谷歌浏览器(Chrome)禁止浏览器缓存 设置
  • 原文地址:https://www.cnblogs.com/shirlybaby/p/13462695.html
Copyright © 2011-2022 走看看