zoukankan      html  css  js  c++  java
  • [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 5168  Solved: 1668
    [Submit][Status][Discuss]

    Description

    小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值) 这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    Input

    第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

    Output

    包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

    Sample Input

    5 6
    1 2 1
    1 3 2
    2 4 3
    3 5 4
    3 4 3
    4 5 6

    Sample Output

    11

    HINT

    数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。

    Source

    [Submit][Status][Discuss]
    
    HOME Back

    题解

    先求出最小生成树,要严格次小
    枚举每一条非树边找俩顶点树链上的最大边(如果最大边相同与非树边边权相同则找次大边)然后更新最小增量
    最大边和次大边可以通过树上倍增求出

    复杂度是最小生成树(mlog m),枚举边乱搞(mlog n),所以是(mlog nm)

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
        for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using namespace std;
    
    co int N=1e5+1,M=3e5+1,INF=0x3f3f3f3f;
    int n,m,t,fa[N],d[N],f[N][18];
    struct edge{
    	int x,y,z,k;
    	bool operator<(co edge&e)co {return z<e.z;}
    }p[M];
    int g[N][18][2];
    ll sum,ans=1e18;
    vector<pair<int,int> > e[N];
    int get(int x) {return fa[x]==x?x:fa[x]=get(fa[x]);}
    void kruskal(){
    	sort(p+1,p+m+1);
    	for(int i=1;i<=n;++i) fa[i]=i;
    	for(int i=1,x,y;i<=m;++i){
    		x=get(p[i].x),y=get(p[i].y);
    		if(x==y) continue;
    		fa[x]=y,sum+=p[i].z,p[i].k=1;
    	}
    }
    void dfs(int x){
    	for(int i=0,y;i<e[x].size();++i){
    		if(d[y=e[x][i].first]) continue;
    		d[y]=d[x]+1;
    		f[y][0]=x;
    		g[y][0][0]=e[x][i].second;
    		g[y][0][1]=-INF;
    		for(int j=1;j<=t;++j){
    			f[y][j]=f[f[y][j-1]][j-1];
    			g[y][j][0]=max(g[y][j-1][0],g[f[y][j-1]][j-1][0]);
    			if(g[y][j-1][0]==g[f[y][j-1]][j-1][0])
    				g[y][j][1]=max(g[y][j-1][1],g[f[y][j-1]][j-1][1]);
    			else if(g[y][j-1][0]<g[f[y][j-1]][j-1][0])
    				g[y][j][1]=max(g[y][j-1][0],g[f[y][j-1]][j-1][1]);
    			else g[y][j][1]=max(g[y][j-1][1],g[f[y][j-1]][j-1][0]);
    		}
    		dfs(y);
    	}
    }
    void lca(int x,int y,int&val1,int&val2){
    	if(d[x]>d[y]) swap(x,y);
    	for(int i=t;i>=0;--i)if(d[f[y][i]]>=d[x]){
    		if(val1>g[y][i][0]) val2=max(val2,g[y][i][0]);
    		else{
    			val1=g[y][i][0];
    			val2=max(val2,g[y][i][1]);
    		}
    		y=f[y][i];
    	}
    	if(x==y) return;
    	for(int i=t;i>=0;--i)if(f[x][i]!=f[y][i]){
    		val1=max(val1,max(g[x][i][0],g[y][i][0]));
    		val2=max(val2,g[x][i][0]!=val1?g[x][i][0]:g[x][i][1]);
    		val2=max(val2,g[y][i][0]!=val1?g[y][i][0]:g[y][i][1]);
    		x=f[x][i],y=f[y][i];
    	}
    	val1=max(val1,max(g[x][0][0],g[y][0][0]));
    	val2=max(val2,g[x][0][0]!=val1?g[x][0][0]:g[x][0][1]);
    	val2=max(val2,g[y][0][0]!=val1?g[y][0][0]:g[y][0][1]);
    }
    int main(){
    	read(n),read(m);
    	for(int i=1;i<=m;++i) read(p[i].x),read(p[i].y),read(p[i].z);
    	kruskal();
    	for(int i=1;i<=m;++i)if(p[i].k)
    		e[p[i].x].push_back(make_pair(p[i].y,p[i].z)),e[p[i].y].push_back(make_pair(p[i].x,p[i].z));
    	t=log(n)/log(2)+1;
    	d[1]=1;
    	for(int i=0;i<=t;++i) g[1][i][0]=g[1][i][1]=-INF;
    	dfs(1);
    	for(int i=1;i<=m;++i)if(!p[i].k){
    		int val1=-INF,val2=-INF;
    		lca(p[i].x,p[i].y,val1,val2);
    		if(p[i].z>val1) ans=min(ans,sum-val1+p[i].z);
    		else ans=min(ans,sum-val2+p[i].z);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    【LeetCode】048. Rotate Image
    【LeetCode】036. Valid Sudoku
    【LeetCode】060. Permutation Sequence
    【LeetCode】001. Two Sum
    【LeetCode】128. Longest Consecutive Sequence
    【LeetCode】081. Search in Rotated Sorted Array II
    【LeetCode】033. Search in Rotated Sorted Array
    顺时针打印矩阵
    矩形覆盖
    二维数组中的查找
  • 原文地址:https://www.cnblogs.com/autoint/p/10935173.html
Copyright © 2011-2022 走看看