【BJWC2010】严格次小生成树【倍增】

2 篇文章 0 订阅
2 篇文章 0 订阅

传送门

借机复习次小生成树。

对于非树边查询最大边权替换更新答案。

这道题不允许边权相等,那就再维护一个次大值。

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();
	}return cnt*f;
}
struct node{
	int u,v,w,flag;
}edge[300003];
int n,m;
int max1[100003][22],max2[100003][22];int f[100003];int all=0;int fa[100003][22];
int first[100003],nxt[200003],to[200003],w[200003],tot;int dep[100003];
void add(int a,int b,int c){nxt[++tot]=first[a];first[a]=tot;to[tot]=b;w[tot]=c;}
int find(int x){if(x==f[x])return f[x];return f[x]=find(f[x]);}
bool cm(node a,node b){return a.w<b.w;}
void dfs(int u,int faa){
	for(int i=1;i<=19;i++){
		fa[u][i]=fa[fa[u][i-1]][i-1];
		max1[u][i]=max(max1[u][i-1],max1[fa[u][i-1]][i-1]);
		max2[u][i]=max(max2[u][i-1],max2[fa[u][i-1]][i-1]);
		if(max1[u][i-1]>max1[fa[u][i-1]][i-1]){max2[u][i]=max(max2[u][i],max1[fa[u][i-1]][i-1]);}
		else if(max1[u][i-1]<max1[fa[u][i-1]][i-1])max2[u][i]=max(max2[u][i],max1[u][i-1]);
	}dep[u]=dep[faa]+1;
	for(int i=first[u];i;i=nxt[i]){
		int v=to[i];if(v==faa)continue;
		max1[v][0]=w[i];max2[v][0]=-0x3f3f3f3f3f3f3f3f;fa[v][0]=u;
		dfs(v,u);
	}
}
int Lca(int a,int b){
	if(dep[a]<dep[b])swap(a,b);
	for(int i=19;i>=0;i--){
		if(dep[fa[a][i]]>=dep[b])a=fa[a][i];
	}
	if(a==b)return a;
	for(int i=19;i>=0;i--){
		if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
	}return fa[a][0];
}int sum;int ans=0x3f3f3f3f3f3f3f3f;
int qmax(int x,int y,int maxx){
	int gu=-0x3f3f3f3f3f3f3f3f;
	for(int i=19;i>=0;i--){
		if(dep[fa[x][i]]>=dep[y]){
			if(maxx!=max1[x][i])gu=max(gu,max1[x][i]);
			else gu=max(gu,max2[x][i]);
			x=fa[x][i];
		}
	}return gu;
}
void query(int x,int y,int key){
	int lca=Lca(x,y);//cout<<"before "<<ans<<endl;
	ans=min(ans,sum-max(qmax(x,lca,key),qmax(y,lca,key))+key);
	//cout<<sum<<" "<<max(qmax(x,lca,key),qmax(y,lca,key))<<" "<<key<<endl;
}
signed main(){
	n=in;m=in;
	for(int i=1;i<=m;i++){int u=in;int v=in;int w=in;edge[i]={u,v,w,0};}
	sort(edge+1,edge+m+1,cm);
	for(int i=1;i<=n;i++)f[i]=i;
	for(int i=1;i<=m;i++){
		int u=edge[i].u,v=edge[i].v;int x=find(u),y=find(v);
		if(x!=y){f[x]=y,++all,edge[i].flag=1,sum+=edge[i].w;}
		if(all==n-1)break;
	}
	for(int i=1;i<=m;i++)if(edge[i].flag)
		add(edge[i].u,edge[i].v,edge[i].w),add(edge[i].v,edge[i].u,edge[i].w);
	max2[1][0]=-0x3f3f3f3f3f3f3f3f;
	dfs(1,0);
	for(int i=1;i<=m;i++){
		if(!edge[i].flag){
			int u=edge[i].u,v=edge[i].v;
			query(u,v,edge[i].w);
		}
	}
	cout<<ans;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值