CF1108F MST Unification(生成树+思维)
首先做一遍最小生成树,其次,如果某条未在生成树当中的边可以替换端点之间的边的话,那么证明它存在新的最小生成树。
因此我们要将这条的权值加到比路径上的最大边大1的情况,才能做到这条边无用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=4e5+10; int h[N],ne[N],e[N],w[N],idx; int depth[N],f[N][30]; ll cost[N][30]; int st[N]; struct node{ ll a,b,c; }s[N]; int n,m; int p[N]; void add(int a,int b,int c){ e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++; } bool cmp(node a,node b){ return a.c<b.c; } void dfs(int u,int fa,int x){ depth[u]=depth[fa]+1; f[u][0]=fa; cost[u][0]=x; int i; for(i=1;i<=24;i++){ f[u][i]=f[f[u][i-1]][i-1]; cost[u][i]=max(cost[f[u][i-1]][i-1],cost[u][i-1]); } for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; dfs(j,u,w[i]); } } int find(int x){ if(p[x]!=x){ p[x]=find(p[x]); } return p[x]; } void kruscal(){ int i; for(i=1;i<=n;i++) p[i]=i; sort(s+1,s+1+m,cmp); int cnt=0; for(i=1;i<=m;i++){ int pa=find(s[i].a); int pb=find(s[i].b); if(pa!=pb){ p[pa]=pb; add(s[i].a,s[i].b,s[i].c); add(s[i].b,s[i].a,s[i].c); cnt++; st[i]=1; } if(cnt==n-1) break; } dfs(1,0,0); } ll lca(int a,int b){ if(depth[a]<depth[b]) swap(a,b); ll res=0; int i; for(i=21;i>=0;i--){ if(depth[f[a][i]]>=depth[b]){ res=max(res,cost[a][i]); a=f[a][i]; } } if(a==b) return res; for(i=21;i>=0;i--){ if(f[a][i]!=f[b][i]){ res=max(res,cost[a][i]); res=max(res,cost[b][i]); a=f[a][i]; b=f[b][i]; } } return max(res,max(cost[a][0],cost[b][0])); } int main(){ ios::sync_with_stdio(false); memset(h,-1,sizeof h); int i; cin>>n>>m; for(i=1;i<=m;i++){ int a,b,c; cin>>a>>b>>c; s[i]={a,b,c}; } kruscal(); ll ans=0; for(i=1;i<=m;i++){ if(st[i]) continue; int a=s[i].a,b=s[i].b; ll x=lca(a,b); if(x==s[i].c){ ans++; } } cout<<ans<<endl; }
没有人不辛苦,只有人不喊疼