洛谷P4180:https://www.luogu.org/problemnew/show/P4180

前言

这可以说是本蒟蒻打过最长的代码了

思路

先求出此图中的最小生成树 权值为tot 我们称这棵树中的n-1条边为“树边” 其他m-n+1条边为“非树边”

枚举每条非树边(x,y,z)添加到最小生成树中 可以在x,y之间构成一个环

设x,y之间的路径最大值为val1 次大值为val2(val1>val2)

则有以下两种情况

  • 当z>val1时 则把val1对应的边换成(x,y,z) 得到一个候选值 权值和为tot-val1+z
  • 当z=val1时 则把val2对应的边换成(x,y,z) 得到一个候选值 权值和为tot-val2+z

在所有候选值中取最小值 即可得出严格次小生成树

求出一条路径上的最大值和次大值可用树上倍增来预处理 设f[x][k]表示x的2k辈祖先

m1[x][k]和m2[x][k]分别为路径上的最大值和次大值

可以得出:

f[x][k]=f[f[x][k-]][k-];
m1[x][k]=max(m1[x][k-],m1[f[x][k-]][k-]);//最大值等于两者中的最大值
if(m1[x][k-]==m1[f[x][k-]][k-])//如果两者中最大值相等
m2[x][k]=max(m2[x][k-],m2[f[x][k-]][k-]);//则取两边次大值中较大的作为次大值
if(m1[x][k-]<m1[f[x][k-]][k-])//如果前面最大小于后面最大
m2[x][k]=max(m1[x][k-],m2[f[x][k-]][k-]);//则取前面最大值与后面次大值中的较大值作为次大值
if(m1[x][k-]>m1[f[x][k-]][k-])//如果前面最大大于后面最大
m2[x][k]=max(m2[x][k-],m1[f[x][k-]][k-]);//则取前面次大值与后面最大值中的较大值作为次大值

当k=0时 各个初始化

f[x][0]=father(x)

m1[x][0]=edge(x,father(x))

m2[x][0]= -INF(不存在次大值)

最后 我们考虑每条非树边 用倍增计算其LCA(x,y)

当x,y每向上移动一段距离 就把该段路径的最大值和次大值合并到答案中

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define maxn 400001
#define ll long long
#define INF 2147483647000000//记得开大 数据很坑
ll n,m,cnt,k,tot,ans=INF;
ll fa[maxn],h[maxn],dep[maxn],f[maxn][],m1[maxn][],m2[maxn][];
bool vis[maxn];
struct Edge
{
ll w;
ll nex;
ll to;
}e[maxn];//最小生成树的变
struct Node
{
ll l,r,w;
}node[maxn];//节点
void add(ll u,ll v,ll w)
{
e[++cnt].to=v;
e[cnt].w=w;
e[cnt].nex=h[u];
h[u]=cnt;
}
bool cmp(Node a,Node b)
{
return a.w<b.w;
}
ll find(ll x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void unionn(ll x,ll y)
{
ll f1=find(x);
ll f2=find(y);
if(f1!=f2)
fa[f1]=f2;
}
void kruskal()//最小生成树
{
sort(node+,node++m,cmp);
for(ll i=;i<=m;i++)
{
if(find(node[i].l)!=find(node[i].r))
{
unionn(node[i].l,node[i].r);
vis[i]=;//判断此边是最小生成树中的边
tot+=node[i].w;//计算最小生成树权值
add(node[i].l,node[i].r,node[i].w);
add(node[i].r,node[i].l,node[i].w);
k++;
}
if(k==n-) break;
}
}
void deal(ll u,ll father)//预处理
{
f[u][]=father;
for(ll i=h[u];i;i=e[i].nex)
{
ll v=e[i].to;
if(v==father) continue;
dep[v]=dep[u]+;//不是父亲时
m1[v][]=e[i].w;//最大值等于此边权值
m2[v][]=-INF;//此大值为极小值 因为此时只有一个值
deal(v,u);
}
}
void pre()//计算出所有的值
{
for(ll x=;x<=;x++)//注意先循环步数
{
for(ll k=;k<=n;k++)
{
f[x][k]=f[f[x][k-]][k-];
m1[x][k]=max(m1[x][k-],m1[f[x][k-]][k-]);//最大值等于两者中的最大值
if(m1[x][k-]==m1[f[x][k-]][k-])//如果两者中最大值相等
m2[x][k]=max(m2[x][k-],m2[f[x][k-]][k-]);//则取两边次大值中较大的作为次大值
if(m1[x][k-]<m1[f[x][k-]][k-])//如果前面最大小于后面最大
m2[x][k]=max(m1[x][k-],m2[f[x][k-]][k-]);//则取前面最大值与后面次大值中的较大值作为次大值
if(m1[x][k-]>m1[f[x][k-]][k-])//如果前面最大大于后面最大
m2[x][k]=max(m2[x][k-],m1[f[x][k-]][k-]);//则取前面次大值与后面最大值中的较大值作为次大值
}
}
}
ll lca(ll x,ll y)//倍增求LCA
{
if(dep[x]<dep[y]) swap(x,y);
for(ll k=;k>=;k--)
{
if(dep[f[x][k]]>=dep[y]) x=f[x][k];
if(x==y) return x;
}
for(ll i=;i>=;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][];
}
ll findmax(ll x,ll t,ll val)//找出最大值
{
ll temp=-INF;
for(ll i=;i>=;i--)
{
if(dep[f[x][i]]>=dep[t])//比LCA深的话
{
if(m1[x][i]==val) temp=max(temp,m2[x][i]);//如果当前最大值等于此路径上最大值 则取次大值替换此边
else temp=max(temp,m1[x][i]);//如果大于最大值 则取最大值替换此边
x=f[x][i];
}
}
return temp;
}
int main()
{
scanf("%lld%lld",&n,&m);
for(ll i=;i<=n;i++) fa[i]=i;
for(ll i=;i<=m;i++) scanf("%lld%lld%lld",&node[i].l,&node[i].r,&node[i].w);
kruskal();
m2[][]=-INF;//初始化
dep[]=;
deal(,);
pre();
for(ll i=;i<=m;i++)//枚举每条非最小生成树边
{
if(vis[i]) continue;//当此边为最小生成树中的边时 跳过
ll x=node[i].l;
ll y=node[i].r;
ll z=node[i].w;
ll t=lca(x,y);
ll v1=findmax(x,t,z);//找出候选最大值 从x到lca(x,y)的路径最大
ll v2=findmax(y,t,z);//从y到lca(x,y)的路径最大
ans=min(ans,tot+z-max(v1,v2));//比较出一个最小值
}
printf("%lld",ans);
}

【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)的更多相关文章

  1. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  2. 【洛谷P4180】严格次小生成树

    题目大意:给定一个 N 个顶点,M 条边的带权无向图,求该无向图的一个严格次小生成树. 引理:有至少一个严格次小生成树,和最小生成树之间只有一条边的差异. 题解: 通过引理可以想到一个暴力,即:先求出 ...

  3. 洛谷P4180 [Beijing2010组队]次小生成树Tree

    题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...

  4. P4180 [BJWC2010]严格次小生成树

    P4180 [BJWC2010]严格次小生成树 P4180 题意 求出一个无向联通图的严格次小生成树.严格次小生成树的定义为边权和大于最小生成树的边权和但不存在另一棵生成树的边权和在最小生成树和严格次 ...

  5. 洛谷P4180 [BJWC2010]次小生成树(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  6. 题解——洛谷P1550 [USACO08OCT]打井Watering Hole(最小生成树,建图)

    题面 题目背景 John的农场缺水了!!! 题目描述 Farmer John has decided to bring water to his N (1 <= N <= 300) pas ...

  7. 洛谷P4180【Beijing2010组队】次小生成树Tree

    题目描述: 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还 ...

  8. bzoj 1977 洛谷P4180 严格次小生成树

    Description: 给定一张N个节点M条边的无向图,求该图的严格次小生成树.设最小生成树边权之和为sum,那么严格次小生成树就是边权之和大于sum的最小的一个 Input: 第一行包含两个整数N ...

  9. [BJWC2010]严格次小生成树(LCA,最小生成树)

    [BJWC2010]严格次小生成树 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图 ...

随机推荐

  1. Bazaar 版本控制工具

    Bazaar是一个分布式的版本控制系统,它发布在GPL许可协议之下,并可用于Windows.GNU/Linux.UNIX以及Mac OS系统.Bazaar由Canonical公司赞助,目前已服务于Sa ...

  2. Excel删除空白行和列

    Sub DeleteEmptyRows() Dim LastRow As Long, r As Long LastRow = ActiveSheet.UsedRange.Rows.Count Last ...

  3. 程序员学炒股(6) 让我们来看一下7月份A股的表现

    有了前几天的数据准备,那让我们看一下7月份的股市是牛市还是熊市呢? 牛市和熊市主要就看股票的涨跌分布情况,虽然我们看大盘数据,但是不过中石油占的A股市值太大了,并且中石油95%的股票都是大股东控制的相 ...

  4. VUE的两种跳转push和replace对比区别

    router.push(location) 在vue.js中想要跳转到不同的 URL,需要使用 router.push 方法. 这个方法会向 history 栈添加一个新的记录,当用户点击浏览器后退按 ...

  5. react相关知识点链接整理

    1.React组件之间的通信 2.中间件做代理解决跨域问题 3.不要再问我跨域的问题了 4.React 组件数据流 && 组件间沟通 5.如何理解虚拟DOM 6.react性能调谐与d ...

  6. 怎样关闭占用80端口的pid为4的进程

    我也被这个问题给纠结了好几天.重装系统都三次了.终于找到原因了:我用的是sqlserver 2008;解决方法:window-sqlserver 2008-配置工具-sqlserver 配置管理器 找 ...

  7. Java读取粘贴板内容

    package com.test.jvm.oom.design; import java.awt.Image; import java.awt.Toolkit; import java.awt.dat ...

  8. Linux基础之-正则表达式(grep,sed,awk)

    一. 正则表达式 正则表达式,又称规则表达式.(英语:Regular Expression,在代码中常简写为regex.regexp或RE),计算机科学的一个概念.正则表达式是对字符串操作的一种逻辑公 ...

  9. OpenfileDialog选择照片的简单应用

    OpenFileDialog openFileDlg = new OpenFileDialog(); openFileDlg.Title = "选择文件"; openFileDlg ...

  10. 【Udacity】解决:字幕遮挡视频内容怎么办?Udacity字幕大小调整

    字幕有没有办法显示在最下方,否则把内容挡住了,根本看不清老师所指的内容 Chrome 的小插件,能方便地调节视频的字幕大小,譬如:Udacity 的学习视频字幕大小不能调节,有时候不想它占太多位置,而 ...