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

    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 leq 2 000) ,(M leq 3 000)(80\%) 的数据 (N leq 50 000), (M leq 100 000)(100\%) 的数据 (Nleq 100 000),(Mleq 300 000) ,边权值非负且不超过 (10^9)


    题解

    首先有一个我并不会证的结论,(严格)次小生成树一定是最小生成树加一条边再删一条边得到的

    回忆非严格次小生成树的做法,先处理出最小生成树上任意两点之间的路径上的最大值,然后枚举添加每一条不在最小生成树上的边 ((u,v)) ,删掉原树上 (u)(v) 路径上的最大值,然后把这条边加入就可以了。

    严格最小生成树与它不同的一点是,我们找的 “原树上 (u)(v) 路径上的最大值” 必须小于 我们要加的边的边权。
    于是用树上倍增 (lca) 来求树上每两点间路径上的最大值和次大值就好了。


    代码

    求次大值是个坑,每次我都有考虑不到的地方……一定要注意注意注意!
    调了好久,我好弱啊……

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    const int N = 100005;
    typedef long long ll;
    
    struct node{
    	int v,len;
    	node *next;
    }pool[N*2],*h[N];
    int cnt;
    void addedge(int u,int v,int len){
    	node *p=&pool[++cnt],*q=&pool[++cnt];
    	p->v=v;p->next=h[u];h[u]=p;p->len=len;
    	q->v=u;q->next=h[v];h[v]=q;q->len=len;
    }
    int n,m;
    int f[N][20],fmax[N][20],gmax[N][20],dep[N];
    void dfs(int u){
    	int v;
    	for(node *p=h[u];p;p=p->next)
    		if(!dep[v=p->v]){
    			dep[v]=dep[u]+1;
    			f[v][0]=u; fmax[v][0]=p->len; gmax[v][0]=0;
    			for(int j=1;j<20;j++){
    				f[v][j]=f[f[v][j-1]][j-1];
    				fmax[v][j]=max(fmax[v][j-1],fmax[f[v][j-1]][j-1]);
    				if(fmax[v][j-1]==fmax[f[v][j-1]][j-1])
    					gmax[v][j]=max(gmax[v][j-1],gmax[f[v][j-1]][j-1]);
    				else {
    					gmax[v][j]=min(fmax[v][j-1],fmax[f[v][j-1]][j-1]);
    					gmax[v][j]=max(gmax[v][j],max(gmax[v][j-1],gmax[f[v][j-1]][j-1]));
    				}
    			}
    			dfs(v);
    		}
    }
    int m1,m2;
    inline void cg(int x,int i){
    	if(fmax[x][i]>m1) m2=max(m1,gmax[x][i]),m1=max(m1,fmax[x][i]);
    	else if(fmax[x][i]<m1) m2=max(m2,fmax[x][i]);
    	else m2=max(m2,gmax[x][i]);
    }
    void getMax(int x,int y){
    	m1=m2=0;
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int i=19;i>=0;i--)
    		if(dep[f[x][i]]>=dep[y])
    			cg(x,i),x=f[x][i];
    	if(x==y) return;
    	for(int i=19;i>=0;i--)
    		if(f[x][i]!=f[y][i]){
    			cg(x,i); cg(y,i);
    			x=f[x][i]; y=f[y][i];
    		}
    	cg(x,0); cg(y,0);
    }
    
    struct edge{
    	int u,v,len,vis;
    	bool operator < (const edge &b) const{ return len<b.len; }
    }ed[N*3];
    int fa[N];
    inline int getfa(int x) { return x==fa[x] ? x : fa[x]=getfa(fa[x]); }
    void unit(int x,int y){
    	x=getfa(x); y=getfa(y);
    	fa[x]=y;
    }
    
    int main()
    {
    	ll ans=0;
    	scanf("%d%d",&n,&m);
    	for(int i=0;i<m;i++) scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].len);
    	
    	sort(ed,ed+m);
    	for(int i=1;i<=n;i++) fa[i]=i;
    	for(int i=0;i<m;i++)
    		if(getfa(ed[i].u)!=getfa(ed[i].v)){
    			ed[i].vis=1;
    			ans+=ed[i].len;
    			unit(ed[i].u,ed[i].v);
    			addedge(ed[i].u,ed[i].v,ed[i].len);
    		}
    	dep[1]=1; dfs(1);
    	
    	int Mx=2*1e9;
    	for(int i=0;i<m;i++)
    		if(!ed[i].vis){
    			getMax(ed[i].u,ed[i].v);
    			if(m1==ed[i].len) Mx=min(Mx,ed[i].len-m2);
    			else Mx=min(Mx,ed[i].len-m1);
    		}
    	printf("%lld
    ",ans+Mx);
    	
    	return 0;
    }
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    MySQL 5.6.9 RC 发布
    红薯 Java 8 的日期时间新用法
    Couchbase Server 2.0 发布,NoSQL 数据库
    Firefox OS 模拟器 1.0 发布
    Calculate Linux 13 Beta 1 发布
    敏捷测试的团队构成
    Node.js 0.8.16 发布(稳定版)
    JASocket 1.1.0 发布
    Samba 4.0 正式版发布,支持活动目录
    Seafile 1.3 发布,文件同步和协作平台
  • 原文地址:https://www.cnblogs.com/lindalee/p/9839154.html
Copyright © 2011-2022 走看看