洛谷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\n",mst+ans);
}
int main(){
read_and_parse();
solve();
return 0;
}
posted on
浙公网安备 33010602011771号