列表

详情


NC50469. 次小生成树

描述

给定一张N个点M条边的无向图,求无向图的严格次小生成树。
设最小生成树的边权之和为,严格次小生成树就是指边权之和大于的生成树中最小的一个。

输入描述

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

输出描述

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

示例1

输入:

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

输出:

11

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 699ms, 内存消耗: 36020K, 提交时间: 2020-01-21 19:05:33

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+1;
const int MAXM = 1e5+1;

int N, M;
struct Edge {
  int u, v, w;
  bool inMst;
};

int p[MAXN];
void init() {
  for (int i = 1; i <= N; i++) p[i] = i;
}
int find(int x) { return p[x] = p[x] == x? x: find(p[x]);}
vector<pair<int, int>> G[MAXN];
int H[MAXN];
int F[MAXN][20];
int V1[MAXN][20];
int V2[MAXN][20];


int get_v(int x, int i, int w) {
  if (V1[x][i] != w) return V1[x][i];
  return V2[x][i];
}
void dfs_lca(int s, int f, int w) {
  F[s][0] = f, H[s] = H[f] + 1;
  V1[s][0] = w, V2[s][0] = -0x3f3f3f3f;
  for (int i = 0; i < 19; i++) {
    int k = F[s][i];
    F[s][i+1] = F[k][i];
    V1[s][i+1] = V1[s][i], V2[s][i+1] = V2[s][i];
    if (V1[k][i] > V1[s][i])  V2[s][i+1] = max(V1[s][i+1], V2[k][i]), V1[s][i+1] = V1[k][i];
    else if (V1[k][i] < V1[s][i]) V2[s][i+1] = max(V1[k][i], V2[s][i]), V1[s][i+1] = V1[s][i];
    else V2[s][i+1] = max(V2[k][i], V2[s][i]), V1[s][i+1] = V1[s][i];
  }
  for (auto it: G[s]) if (it.first != f) dfs_lca(it.first, s, it.second);
}
int get(int x, int y, int w) {
  int ans = -0x3f3f3f3f;
  if (H[x] < H[y]) swap(x, y);
  for (int i = 19; i >= 0; i--) if (H[F[x][i]] >= H[y]) {
    ans = max(ans, get_v(x, i, w));
    x = F[x][i];
  }
  if (x == y) return ans;
  for (int i = 19; i >= 0; i--) if (F[x][i] != F[y][i]) {
    ans = max(ans, get_v(x, i, w));
    ans = max(ans, get_v(y, i, w));
    x = F[x][i], y = F[y][i];
  }
  ans = max(ans, get_v(x, 0, w));
  ans = max(ans, get_v(y, 0, w));
  return ans;
}

int main() {
  ios_base::sync_with_stdio(false);
  cin >> N >> M;
  vector<Edge> edges(M); for(auto &e: edges) cin>> e.u >> e.v >> e.w;
  sort(edges.begin(), edges.end(), [](const Edge &l, const Edge &r) {
    return l.w < r.w;
  });
  init();
  int cnt = 0;
  long long mst = 0;
  for (auto &e: edges) {
    int x = e.u, y = e.v;
    int px = find(x), py = find(y);
    if (px == py) continue;
    p[px] = py;
    G[x].push_back({y, e.w});
    G[y].push_back({x, e.w});
    e.inMst = true;
    mst += e.w;
    if (++cnt == N - 1) break;
  }
  dfs_lca(1, 0, 0);

  long long ans = 0x3f3f3f3f3f3f3f3f;
  for (auto &e: edges) if (!e.inMst) {
    int t = get(e.u, e.v, e.w);
    if (t == -0x3f3f3f3f) continue;
    ans = min(ans, mst + e.w - t);
  }
  cout << ans << endl;
}

C++(clang++11) 解法, 执行用时: 274ms, 内存消耗: 34912K, 提交时间: 2020-11-04 20:16:13

#include<bits/stdc++.h>
#define eb emplace_back
#define pii pair<int,int>
#define mp make_pair
using namespace std;
const int nn=101104,mm=301104;
int n,m,ans=INT_MAX,fa[nn],dep[nn];
int f[nn][20],g[nn][20][2];
long long sum;
vector<pii>son[nn];
struct edge{int x,y,z;}e[mm];
bool cmp(edge a,edge b){return a.z<b.z;}
int get(int i){return fa[i]==i?i:fa[i]=get(fa[i]);}
void up(int a,int b,int c,int d,int&x,int&y){
	x=max(a,b);
	if(a==b)y=max(c,d);
	else if(a<b)y=max(a,d);
		else y=max(b,c);
}void dfs(int u){
	dep[u]++;
	for(int i=0;f[u][i];i++)
		f[u][i+1]=f[f[u][i]][i],
		up(g[u][i][0],g[f[u][i]][i][0],
		g[u][i][1],g[f[u][i]][i][1],
		g[u][i+1][0],g[u][i+1][1]);
	for(int i=0,v;i<(int)son[u].size();i++)
		if((v=son[u][i].first)!=f[u][0])
			f[v][0]=u,g[v][0][0]=son[u][i].second,
			dep[v]=dep[u],dfs(v);
}int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=0;i<m;i++)
		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
	sort(e,e+m,cmp);
	for(int i=0,x,y,z;i<m;i++)
		if(get(x=e[i].x)!=get(y=e[i].y))
			fa[get(x)]=get(y),sum+=(z=e[i].z),
			son[x].eb(mp(y,z)),son[y].eb(mp(x,z));
	dfs(1);for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=0,x,y,a,b,d;i<m;i++)
		if(get(x=e[i].x)==get(y=e[i].y)){
			if(dep[x]<dep[y])swap(x,y);
			a=b=0,d=dep[x]-dep[y];
			for(int j=0;d;d>>=1,j++)if(d&1)
				up(a,g[x][j][0],b,g[x][j][1],a,b),x=f[x][j];
			if(x!=y){
				for(int j=18;j>=0;j--)if(f[x][j]!=f[y][j])
					up(a,g[x][j][0],b,g[x][j][1],a,b),
					up(a,g[y][j][0],b,g[y][j][1],a,b), 
					x=f[x][j],y=f[y][j];
				up(a,g[x][0][0],b,g[x][0][1],a,b),x=f[x][0],
				up(a,g[y][0][0],b,g[y][0][1],a,b),y=f[y][0];
			}if(e[i].z>a)ans=min(ans,e[i].z-a);
			else if(b)ans=min(ans,e[i].z-b);
		}else fa[get(x)]=get(y);
	return printf("%lld",sum+ans),0;
}

上一题