题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977
kruscal别忘了先按边权sort。自己觉得那部分处理得还挺好的。(联想到之前某题的经验)
没管重边。好像还行?
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define ll long long using namespace std; const int N=1e5+5,M=3e5+5,Lm=20,INF=1e9+7; int n,m,head[N],xnt=1,pre[N][Lm+5],mx[N][Lm+5][2]; int fa[N],dis[N],fr[N],dep[N]; ll ans,zl; bool vis[N],use[M<<1]; struct Ed{ int next,fr,to,w,bh; Ed(int n=0,int f=0,int t=0,int w=0):next(n),fr(f),to(t),w(w) {} bool operator< (const Ed &b)const {return bh<b.bh;} }ed[M<<1]; void add(int x,int y,int z) { ed[++xnt]=Ed(head[x],x,y,z);head[x]=xnt;ed[xnt].bh=xnt; ed[++xnt]=Ed(head[y],y,x,z);head[y]=xnt;ed[xnt].bh=xnt; } int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);} bool cmp(Ed u,Ed v){return u.w<v.w;} void kruscal() { sort(ed+2,ed+xnt+1,cmp);//////// for(int i=1;i<=n;i++)fa[i]=i; for(int i=2;i<=xnt;i++) if(find(ed[i].fr)!=find(ed[i].to)) { use[ed[i].bh]=1;ans+=ed[i].w; fa[find(ed[i].fr)]=find(ed[i].to); } sort(ed+2,ed+xnt+1);//为了^1 for(int i=2;i<=xnt;i++)if(use[i])use[i^1]=1; } void dfs(int cr,int r) { pre[cr][0]=ed[r].fr;mx[cr][0][0]=ed[r].w;dep[cr]=dep[ed[r].fr]+1; for(int i=1;i<=Lm;i++) { int k=pre[cr][i-1];if(!pre[k][i-1])break; pre[cr][i]=pre[k][i-1]; mx[cr][i][0]=max(mx[cr][i-1][0],mx[k][i-1][0]); mx[cr][i][1]=max(mx[cr][i-1][1],mx[k][i-1][1]); if(mx[cr][i-1][0]<mx[cr][i][0])mx[cr][i][1]=max(mx[cr][i][1],mx[cr][i-1][0]); if(mx[k][i-1][0]<mx[cr][i][0])mx[cr][i][1]=max(mx[cr][i][1],mx[k][i-1][0]); } for(int i=head[cr];i;i=ed[i].next) if(use[i]&&i!=(r^1)/*&&!pre[ed[i].to][0]*/)dfs(ed[i].to,i); } void cz(int &w0,int &w1,int x,int i) { int tmp=w0; w0=max(w0,mx[x][i][0]);w1=max(w1,mx[x][i][1]); if(tmp<w0)w1=max(w1,tmp); else if(mx[x][i][0]!=w0)w1=max(w1,mx[x][i][0]);//严格次大 } void solve(int x,int y,int &w0,int &w1) { if(dep[x]<dep[y])swap(x,y); for(int i=Lm;i>=0;i--) if(dep[pre[x][i]]>=dep[y]) cz(w0,w1,x,i),x=pre[x][i]; if(x==y)return; for(int i=Lm;i>=0;i--) if(pre[x][i]!=pre[y][i]) { cz(w0,w1,x,i);cz(w0,w1,y,i); x=pre[x][i];y=pre[y][i]; } if(x!=y) { cz(w0,w1,x,0);cz(w0,w1,y,0); x=pre[x][0];y=pre[y][0]; } } int main() { scanf("%d%d",&n,&m);int x,y,z; for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z);add(x,y,z); } kruscal(); dfs(1,0);zl=INF; for(int i=2;i<=xnt;i+=2) if(!use[i]) { int w0=-1,w1=-1; solve(ed[i].fr,ed[i].to,w0,w1); if(ed[i].w>w0)zl=min(zl,(ll)ed[i].w-w0); else if(ed[i].w>w1)zl=min(zl,(ll)ed[i].w-w1); } printf("%lld",ans+zl); return 0; }