[Educational Round 3][Codeforces 609E. Minimum spanning tree for each edge]

這題原本是想放在educational round 3的題解裏的,但以爲頗有意思就單獨拿出來寫了html

題目連接:609E - Minimum spanning tree for each edgec++

題目大意:n個點,m條邊,對每條邊,詢問包含此邊的最小生成樹的邊權之和算法

題解:大部分人都是用LCA寫的,這裏提供一個更爲精妙的作法。ide

   模擬Kruskal算法建MST的過程,先將m條邊按邊權排序,依次進行判斷。若點對(u,v)屬於同一個連通塊,則加入邊{u,v,w}後會造成一個環,把環中最大的邊換成w會多產生的權重就是包含這條邊的MST比原先的MST多出來的權重,不然在MST中加入這條邊。spa

   而這裏加邊的時候並非選擇直接在(u,v)之間連邊,而是在他們的祖先之間連邊,並有以下判斷:若點v的子樹大小大於點u的子樹大小,則把v看作是u的父親(將u所在的子樹併入v),反之亦然。判斷加邊後是否會成環時,則只需暴力一層層尋找當前點的父親便可,便是用O(n)的方法求LCA,但因爲以前建樹的方式用到了[small to large]的思想(就是啓發式合併),因此往上爬的層數不會超過log n。所以時間複雜度爲O(mlog n)。code

#include<bits/stdc++.h>
using namespace std; #define N 200001
#define LL long long
struct rua{LL u,v,w,id;}a[N]; LL n,m,mst,fa[N],f[N],sz[N],l[N]; bool cmp(rua x,rua y){return x.w<y.w;} LL add(LL u,LL v,LL w) { LL mx=0; while((fa[u]!=u ||fa[v]!=v) && u!=v) if(fa[u]==u || (fa[v]!=v && sz[v]<=sz[u])) mx=max(mx,l[v]),v=fa[v]; else mx=max(mx,l[u]),u=fa[u]; if(u==v)return w-mx; if(sz[u]<sz[v])swap(u,v); sz[u]+=sz[v],fa[v]=u,l[v]=w; return mst+=w,0; } int main() { scanf("%I64d%I64d",&n,&m); for(int i=1;i<=m;i++) scanf("%I64d%I64d%I64d",&a[i].u,&a[i].v,&a[i].w),sz[i]=1,fa[i]=a[i].id=i; sort(a+1,a+m+1,cmp); for(int i=1;i<=m;i++) f[a[i].id]=add(a[i].u,a[i].v,a[i].w); for(int i=1;i<=m;i++) printf("%I64d\n",mst+f[i]); }
View Code
相關文章
相關標籤/搜索