#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>usingnamespace std;typedeflonglong LL;constint N =510, M =10010;int n, m;struct Edge
{int a, b, w;bool f;booloperator<(const Edge &t)const{return w < t.w;}}edge[M];int p[N];int dist1[N][N], dist2[N][N];int h[N], e[N *2], w[N *2], ne[N *2], idx;voidadd(int a,int b,int c){
e[idx]= b, w[idx]= c, ne[idx]= h[a], h[a]= idx ++;}intfind(int x){if(p[x]!= x) p[x]=find(p[x]);return p[x];}voiddfs(int u,int fa,int maxd1,int maxd2,int d1[],int d2[])//求以某一个点为根节点{//的时候,每一个点到该节点的路径
d1[u]= maxd1, d2[u]= maxd2;//上的最长边和次长边for(int i = h[u];~i; i = ne[i]){int j = e[i];if(j != fa){int td1 = maxd1, td2 = maxd2;if(w[i]> td1) td2 = td1, td1 = w[i];elseif(w[i]< td1 && w[i]> td2) td2 = w[i];dfs(j, u, td1, td2, d1, d2);}}}intmain(){scanf("%d%d",&n,&m);memset(h,-1,sizeof h);for(int i =0; i < m; i ++){int a, b, w;scanf("%d%d%d",&a,&b,&w);
edge[i]={a, b, w};}sort(edge, edge + m);for(int i =1; i <= n; i ++) p[i]= i;
LL sum =0;for(int i =0; i < m; i ++)//Kruskal算法求最小生成树{int a = edge[i].a, b = edge[i].b, w = edge[i].w;int pa =find(a), pb =find(b);if(pa != pb){
p[pa]= pb;
sum += w;add(a, b, w),add(b, a, w);
edge[i].f =true;//标记一下是最小生成树上的边}}for(int i =1; i <= n; i ++)dfs(i,-1,-1e9,-1e9, dist1[i], dist2[i]);//dfs求一下任意两点之间路径上最长边
LL res =1e18;for(int i =0; i < m; i ++)//枚举一下所有不是最小生成树上的边if(!edge[i].f){int a = edge[i].a, b = edge[i].b, w = edge[i].w;
LL t;if(w > dist1[a][b])//如果这条边比u到v的路径中的最大边还大 那么可以替换 不然替换了反而变小
t = sum + w - dist1[a][b];elseif(w > dist2[a][b])//如果和最大的边相等 那么判断是否大于次大边
t = sum + w - dist2[a][b];
res =min(res, t);}printf("%lld\n", res);return0;}
LCA
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>usingnamespace std;typedeflonglong LL;constint N =100010, M =300010, INF =0x3f3f3f3f;int n, m;struct Edge
{int a, b, w;bool used;booloperator<(const Edge &t)const{return w < t.w;}}edge[M];int p[N];int h[N], e[M], w[M], ne[M], idx;int depth[N], fa[N][17], d1[N][17], d2[N][17];// depth 表示的是每一个树中节点层数,fa表示某个节点的祖先// d1表示某个节点到祖先的最大边,d2则是次大边int q[N];voidadd(int a,int b,int c){
e[idx]= b, w[idx]= c, ne[idx]= h[a], h[a]= idx ++;}intfind(int x){if(p[x]!= x) p[x]=find(p[x]);return p[x];}
LL kruskal(){for(int i =1; i <= n; i ++) p[i]= i;sort(edge, edge + m);
LL res =0;for(int i =0; i < m; i ++){int a =find(edge[i].a), b =find(edge[i].b), w = edge[i].w;if(a != b){
p[a]= b;
res += w;
edge[i].used =true;}}return res;}voidbuild(){memset(h,-1,sizeof h);for(int i =0; i < m; i ++)if(edge[i].used){int a = edge[i].a, b = edge[i].b, w = edge[i].w;add(a, b, w),add(b, a, w);}}voidbfs(){memset(depth,0x3f,sizeof depth);
depth[0]=0, depth[1]=1;
q[0]=1;int hh =0, tt =0;while(hh <= tt){int t = q[hh ++];for(int i = h[t];~i; i = ne[i]){int j = e[i];if(depth[j]> depth[t]+1)//如果当前点没有被遍历过{
depth[j]= depth[t]+1;
q[++ tt]= j;
fa[j][0]= t;//j的前一个祖先就是t
d1[j][0]= w[i], d2[j][0]=-INF;//最大边初始化为w[i],因为只有一条边,所以次大边初始化为-INFfor(int k =1; k <=16; k ++)//枚举该点的每一个祖先{int anc = fa[j][k -1];
fa[j][k]= fa[anc][k -1];//j点祖先赋值// 最大值和次大值只可能从以下四个值中选int distance[4]={d1[j][k -1], d2[j][k -1], d1[anc][k -1], d2[anc][k -1]};
d1[j][k]= d2[j][k]=-INF;for(int u =0; u <4; u ++)//枚举取得最大值和次大值{int d = distance[u];if(d > d1[j][k]) d2[j][k]= d1[j][k], d1[j][k]= d;elseif(d != d1[j][k]&& d > d2[j][k]) d2[j][k]= d;}}}}}}intlca(int a,int b,int w){//由于最后a到b上所有边的最大值和次大值staticint distance[N *2];int cnt =0;if(depth[a]< depth[b])swap(a, b);for(int k =16; k >=0; k --)if(depth[fa[a][k]]>= depth[b]){
distance[cnt ++]= d1[a][k];
distance[cnt ++]= d2[a][k];
a = fa[a][k];}if(a != b){for(int k =16; k >=0; k --)if(fa[a][k]!= fa[b][k]){
distance[cnt ++]= d1[a][k];
distance[cnt ++]= d2[a][k];
distance[cnt ++]= d1[b][k];
distance[cnt ++]= d2[b][k];
a = fa[a][k], b = fa[b][k];}//别忘记最后找到公共祖先时候还有两条边要加入
distance[cnt ++]= d1[a][0];
distance[cnt ++]= d1[b][0];}int dist1 =-INF, dist2 =-INF;for(int i =0; i < cnt; i ++){int d = distance[i];if(d > dist1) dist2 = dist1, dist1 = d;elseif(d != dist1 && d > dist2) dist2 = d;}//如果大于最大边就直接替换if(w > dist1)return w - dist1;//如果和最大边相等就看一下是否大于次大边if(w > dist2)return w - dist2;return INF;}intmain(){scanf("%d%d",&n,&m);for(int i =0; i < m; i ++){int a, b, c;scanf("%d%d%d",&a,&b,&c);
edge[i]={a, b, c};}
LL sum =kruskal();build();bfs();
LL res =1e18;for(int i =0; i < m; i ++)//枚举每一条不在树上的边if(!edge[i].used){int a = edge[i].a, b = edge[i].b, w = edge[i].w;
res =min(res, sum +lca(a, b, w));}printf("%lld\n", res);return0;}
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int N = 510, M = 10010;int n, m;struct Edge{ int a, b, w; bool f; bool operator< (c