ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF609E Minimum spanning tree for each edge 【最小生成树+树链剖分】

2022-08-24 11:02:58  阅读:66  来源: 互联网

标签:const 剖分 res tree CF609E 生成 最小 权值 条边


CF609E Minimum spanning tree for each edge

题目描述

给你 \(n\) 个点,\(m\) 条边,如果对于一个最小生成树中要求必须包括第 \(i (1 \le i \le m)\) 条边,那么最小生成树的权值总和最小是多少。

输入格式

第一行 \(n,m\) ,后面 \(m\) 行每行 \(u,v,w\) 代表一条边。

输出格式

\(m\) 行,第 \(i\) 行一个整数代表包括第 \(i\) 条边时的最小权值和。


首先考虑构建一颗最小生成树,如果在最小生成树上的边权值就是最小生成树的权值了,否则,如果我们加上这条边,就会在原来的树上形成一个环,我们想让这个图变回一棵树,就需要在环上去掉一条边,为了保证构成的树最小,所以要去掉这个环上边权最大的边,去掉的这个边肯定在原图最小生成树上,所以树链剖分维护最小生成树的最大边权就可以了。

Code.

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;
struct node
{
	int u,v,w,id;
	bool operator < (const node &o) const {
		return w < o.w;
	}
} a[N];
struct Seg {int l,r,mx;} tr[N<<2]; ll ans[N],res;
int p[N],h[N],ne[N<<1],e[N<<1],w[N<<1],idx,n,m,dep[N],sz[N],son[N],val[N],id[N],cnt,top[N],fa[N],pl[N];
void add(int u,int v,int c) {ne[++idx]=h[u],e[idx]=v,w[idx]=c,h[u]=idx;}
int find(int x) {if(p[x] != x) p[x]=find(p[x]); return p[x];}
void dfs(int u,int father,int depth)
{
	sz[u]=1; fa[u]=father; dep[u]=depth;
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i]; if(j == father) continue ;
		val[j]=w[i]; dfs(j,u,depth+1); sz[u]+=sz[j];
		if(sz[son[u]] < sz[j]) son[u]=j;
	}
}
void dfs2(int u,int t)
{
	id[u]=++cnt; top[u]=t; pl[cnt]=val[u];
	if(! son[u]) return ; dfs2(son[u],t);
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i]; if(j == fa[u] || j == son[u]) continue ;
		dfs2(j,j);
	}
}
void pushup(int u) {tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx);}
void build(int u,int l,int r)
{
	tr[u].l=l; tr[u].r=r;
	if(l == r) return tr[u].mx=pl[l],void();
	int mid = l + r >> 1;
	build(u<<1,l,mid); build(u<<1|1,mid+1,r);
	pushup(u);
}
int query(int u,int l,int r)
{
	if(l <= tr[u].l &&  tr[u].r <= r) return tr[u].mx;
	int mid = tr[u].l + tr[u].r >> 1,res=0;
	if(l <= mid) res=max(res,query(u<<1,l,r));
	if(r > mid) res=max(res,query(u<<1|1,l,r));
	return res;
}
int q_query(int u,int v)
{
	int res=0;
	while(top[u] != top[v])
	{
		if(dep[top[u]] < dep[top[v]]) swap(u,v);
		res=max(res,query(1,id[top[u]],id[u])); u=fa[top[u]];
	}
	if(dep[u] < dep[v]) swap(u,v); res=max(res,query(1,id[v]+1,id[u]));
	return res;
}
int main()
{
	memset(h,-1,sizeof h); scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w),a[i].id=i;
	for(int i=1;i<=n;i++) p[i]=i;
	stable_sort(a+1,a+1+m);
	for(int i=1;i<=m;i++)
	{
		int u=a[i].u,v=a[i].v; u=find(u); v=find(v); if(u == v) continue ;
		p[u]=v; res+=a[i].w; add(a[i].u,a[i].v,a[i].w); add(a[i].v,a[i].u,a[i].w);
	}
	dfs(1,0,1); dfs2(1,1); build(1,1,n);
	for(int i=1;i<=m;i++) ans[a[i].id]=res+a[i].w-q_query(a[i].u,a[i].v);
	for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
	return 0;
}

标签:const,剖分,res,tree,CF609E,生成,最小,权值,条边
来源: https://www.cnblogs.com/EastPorridge/p/16619069.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有