1. 程式人生 > 其它 >cf609e Minimum spanning tree for each edge

cf609e Minimum spanning tree for each edge

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;
}