cf609e Minimum spanning tree for each edge
阿新 • • 發佈:2021-08-04
cf609e Minimum spanning tree for each edge
有一個 \(n\) 個頂點,\(m\) 條邊的帶權無向圖 .
對於圖上的每一條邊,求含有邊 \((u,v)\) 的最小生成樹大小 .
\(1\leq n\leq 2\cdot 10^5,n-1\leq m\leq 2\cdot 10^5,1\leq u_i,v_i\leq n,u_i\not=v_i,1\leq w_i\leq 10^9\)
這是我們學校資訊特長生考試的原題,但是我由於程式碼能力太爛,考試的時候並沒有做出來. qwq
可以對於整個圖先求出一個最小生成樹 \(T\) .
對於在 \(T\) 上的邊最小生成大小就是 \(T\)
對於不在 \(T\) 上的邊連上之後就是一個環,那麼,這個環上必須要斷掉一條邊,斷掉代價除了當前這條邊最大的邊 .
那麼,可以求出 \(u,v\) 的最小公共祖先 \(r\) ,那麼,環就是 \(u\rightarrow r\rightarrow v\rightarrow u\) 樣子的,但是 \((v,u)\) 這條邊是不可以選的 . 那麼,能選的是 \(u\rightarrow r\) , \(v\rightarrow r\) 這兩條鏈 .
因為這題不需要支援動態修改,可以用倍增實現,第一次用倍增維護區間最小值 . OwO 感覺自己又會了一個厲害的東西呢.
其實,可以在求lca的時候同時實現,但是我是單獨實現的.
時間複雜度 : \(O(n\log n+m\log n)\)
空間複雜度 : \(O(n\log n)\)
第一次提交 : Accepted
Code
#include<bits/stdc++.h> using namespace std; const int inf=1e9+10; int n,m; int w[200010],fa[200010]; bool tree[200010]; vector<pair<int,int> >e,g[200010]; inline int get_fa(int x){ return fa[x]==x?x:fa[x]=get_fa(fa[x]); } inline void merge(int u,int v){ u=get_fa(u);v=get_fa(v); if(u==v)return; fa[u]=v; } int dep[200010]; int nxt[200010][20],mv[200010][20]; void dfs(int x,int fa){ nxt[x][0]=fa; for(int i=0;i<(int)g[x].size();i++){ int to=g[x][i].first,id=g[x][i].second; if(to==fa)continue; dep[to]=dep[x]+1; mv[to][0]=w[id]; dfs(to,x); } } void build(){ for(int k=0;k+1<20;k++){ for(int i=0;i<n;i++){ if(nxt[i][k]==-1)nxt[i][k+1]=-1; else{ nxt[i][k+1]=nxt[nxt[i][k]][k]; mv[i][k+1]=max(mv[i][k],mv[nxt[i][k]][k]); } } } } int lca(int u,int v){ if(dep[u]>dep[v])swap(u,v); for(int k=0;k<20;k++){ if((dep[u]-dep[v])>>k&1){ v=nxt[v][k]; } } if(u==v)return u; for(int k=19;k>=0;k--){ if(nxt[u][k]!=nxt[v][k]){ u=nxt[u][k]; v=nxt[v][k]; } } return nxt[u][0]; } int main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(); cin>>n>>m; for(int i=0;i<m;i++){ int u,v; cin>>u>>v>>w[i]; u--;v--; e.push_back(make_pair(u,v)); } vector<pair<int,int> >v; for(int i=0;i<m;i++)v.push_back(make_pair(w[i],i)); sort(v.begin(),v.end()); for(int i=0;i<n;i++)fa[i]=i; long long ans=0; for(int i=0;i<m;i++){ int id=v[i].second; int u=e[id].first,v=e[id].second; if(get_fa(u)==get_fa(v))continue; merge(u,v); ans+=w[id]; tree[id]=true; g[u].push_back(make_pair(v,id)); g[v].push_back(make_pair(u,id)); } dfs(0,-1); build(); for(int i=0;i<m;i++){ if(tree[i]){ cout<<ans<<endl; continue; } int u=e[i].first,v=e[i].second; int r=lca(u,v); int tmp=0; for(int k=19;k>=0;k--){ if(nxt[u][k]==-1)continue; if(dep[nxt[u][k]]>=dep[r]){ tmp=max(tmp,mv[u][k]); u=nxt[u][k]; } } for(int k=19;k>=0;k--){ if(nxt[v][k]==-1)continue; if(dep[nxt[v][k]]>=dep[r]){ tmp=max(tmp,mv[v][k]); v=nxt[v][k]; } } cout<<ans-tmp+w[i]<<endl; } return 0; }